rawbotz 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -5
  3. data/Gemfile +2 -0
  4. data/README.md +60 -6
  5. data/Rakefile +3 -2
  6. data/agpl-3.0.txt +661 -0
  7. data/exe/bcrypt_pw +10 -0
  8. data/exe/rawbotz_abort_orders +28 -0
  9. data/exe/rawbotz_process_order_queue +12 -8
  10. data/exe/rawbotz_stock_update +10 -1
  11. data/exe/rawbotz_update_local_products +11 -3
  12. data/exe/rawbotz_update_remote_products +27 -4
  13. data/lib/rawbotz.rb +13 -5
  14. data/lib/rawbotz/app.rb +36 -2
  15. data/lib/rawbotz/cli/order_result_table.rb +13 -0
  16. data/lib/rawbotz/helpers/format_helper.rb +14 -0
  17. data/lib/rawbotz/helpers/icon_helper.rb +108 -22
  18. data/lib/rawbotz/helpers/order_item_color_helper.rb +17 -0
  19. data/lib/rawbotz/helpers/resource_link_helper.rb +3 -0
  20. data/lib/rawbotz/mail_template.rb +42 -7
  21. data/lib/rawbotz/models/sales.rb +21 -0
  22. data/lib/rawbotz/models/stock.rb +25 -0
  23. data/lib/rawbotz/models/stock_product.rb +146 -0
  24. data/lib/rawbotz/models/stock_product_factory.rb +64 -0
  25. data/lib/rawbotz/processors/order_linker.rb +50 -0
  26. data/lib/rawbotz/{order_processor.rb → processors/order_processor.rb} +14 -3
  27. data/lib/rawbotz/processors/organic_product_deliveries_csv.rb +47 -0
  28. data/lib/rawbotz/{product_updater.rb → processors/product_updater.rb} +71 -6
  29. data/lib/rawbotz/processors/stock_processor.rb +67 -0
  30. data/lib/rawbotz/public/rawbotz.css +35 -1
  31. data/lib/rawbotz/public/rawbotz.js +0 -1
  32. data/lib/rawbotz/remote_shop.rb +3 -0
  33. data/lib/rawbotz/routes.rb +3 -0
  34. data/lib/rawbotz/routes/non_remote_orders.rb +129 -29
  35. data/lib/rawbotz/routes/orders.rb +55 -4
  36. data/lib/rawbotz/routes/orders/stock.rb +75 -0
  37. data/lib/rawbotz/routes/product_links.rb +1 -1
  38. data/lib/rawbotz/routes/products.rb +19 -22
  39. data/lib/rawbotz/routes/remote_shop.rb +1 -1
  40. data/lib/rawbotz/routes/stock.rb +58 -0
  41. data/lib/rawbotz/routes/suppliers.rb +9 -4
  42. data/lib/rawbotz/sales_data.rb +13 -0
  43. data/lib/rawbotz/version.rb +1 -1
  44. data/lib/rawbotz/views/_hide_unhide_button.haml +1 -1
  45. data/lib/rawbotz/views/_menu.haml +9 -0
  46. data/lib/rawbotz/views/index.haml +1 -1
  47. data/lib/rawbotz/views/layout.haml +0 -1
  48. data/lib/rawbotz/views/order/_head.haml +64 -19
  49. data/lib/rawbotz/views/order/_item_table.haml +19 -3
  50. data/lib/rawbotz/views/order/_order_actions.haml +26 -0
  51. data/lib/rawbotz/views/order/link_to_remote.haml +30 -0
  52. data/lib/rawbotz/views/order/non_remote.haml +120 -26
  53. data/lib/rawbotz/views/order/packlist.haml +62 -5
  54. data/lib/rawbotz/views/order/packlist.pdf.haml +35 -0
  55. data/lib/rawbotz/views/order/stock.haml +116 -0
  56. data/lib/rawbotz/views/order/view.haml +41 -21
  57. data/lib/rawbotz/views/orders/_order_table.haml +82 -0
  58. data/lib/rawbotz/views/orders/index.haml +41 -28
  59. data/lib/rawbotz/views/orders/menu.haml +2 -2
  60. data/lib/rawbotz/views/orders/non_remotes.haml +14 -3
  61. data/lib/rawbotz/views/pdf_layout.haml +44 -0
  62. data/lib/rawbotz/views/product/view.haml +64 -11
  63. data/lib/rawbotz/views/products/index.haml +1 -1
  64. data/lib/rawbotz/views/products/table.haml +5 -1
  65. data/lib/rawbotz/views/remote_cart/index.haml +10 -0
  66. data/lib/rawbotz/views/remote_order/view.haml +6 -4
  67. data/lib/rawbotz/views/remote_orders/index.haml +16 -13
  68. data/lib/rawbotz/views/stock/index.haml +119 -0
  69. data/lib/rawbotz/views/stock/menu.haml +20 -0
  70. data/lib/rawbotz/views/stock_product/_value_table_line.haml +22 -0
  71. data/lib/rawbotz/views/stock_product/value_table.haml +28 -0
  72. data/lib/rawbotz/views/stockexplorer/stockexplorer.haml +157 -0
  73. data/lib/rawbotz/views/supplier/orders/table.haml +26 -0
  74. data/lib/rawbotz/views/supplier/view.haml +56 -10
  75. data/rawbotz.gemspec +13 -9
  76. metadata +86 -17
  77. data/lib/rawbotz/views/order/new.haml +0 -22
@@ -4,6 +4,12 @@
4
4
 
5
5
  %form.pure-form.pure-form-aligned(action="" method="post")
6
6
  %input(type="hidden" name="_method" value="put")
7
+ - if @product.hidden?
8
+ .ui-state-error
9
+ This product is hidden (in rawbotz).
10
+ - if !@product.active?
11
+ .ui-state-error
12
+ This product is deactivated (in magento).
7
13
  %fieldset
8
14
  .pure-control-group
9
15
  %label(for="product_id") Product ID
@@ -21,29 +27,52 @@
21
27
  .pure-control-group
22
28
  %label(for="supplier") Supplier
23
29
  = supplier_link @product.supplier
24
- .pure-control-group
25
- %label(for="supplier") Remote Product
26
- - if @product.remote_product.nil?
27
- %a(href="/product/#{@product.id}/link") Link to ...
28
- - else
29
- = remote_product_link @product
30
+ - if @product.supplier == settings.supplier || @product.remote_product.present?
31
+ .pure-control-group
32
+ %label(for="supplier") Remote Product
33
+ - if @product.supplier != settings.supplier
34
+ = error_icon
35
+ = remote_product_link @product
36
+ (but not from remote shop!)
37
+ - elsif @product.remote_product.nil?
38
+ not linked
39
+ %a(href="/product/#{@product.id}/link") Linking View
40
+ - else
41
+ = remote_product_link @product
42
+ - if @product.supplier == settings.supplier || @product.remote_product.present?
43
+ .pure-control-group
44
+ %label(for="remote_frontend") Remote Frontend Product page
45
+ %a(href="#{Rawbotz::RemoteShop.product_page_url(@product, settings.conf)}" target="remote_shop")
46
+ = Rawbotz::RemoteShop.product_page_url(@product, settings.conf)
30
47
  .pure-control-group
31
48
  %label(for="packsize") Pack size
32
49
  = @product.packsize
33
50
  .pure-control-group
34
51
  %label(for="shelve") Shelve
35
52
  = @product.shelve_nr
36
- - if @product.supplier_sku != ""
53
+ - if @product.supplier_sku.present?
37
54
  .pure-control-group
38
55
  %label(for="supplier_sku") Supplier SKU
39
56
  = @product.supplier_sku
40
- - if @product.supplier_prod_name != ""
57
+ - if @product.supplier_prod_name.present?
41
58
  .pure-control-group
42
59
  %label(for="supplier_prod_name") Supplier Product Name
43
60
  = @product.supplier_prod_name
61
+ - if @product.order_info.present?
62
+ .pure-control-group
63
+ %label(for="order_info") Order Info
64
+ = @product.order_info
65
+ - if @product.purchase_price.present?
66
+ .pure-control-group
67
+ %label(for="purchase_price") Purchase Price
68
+ = @product.purchase_price
69
+ .pure-control-group
70
+ %label(for="organic") Organic
71
+ = bool_icon @product.organic?
72
+
44
73
 
45
74
  %h2 Actions
46
- - if !@product.remote_product.present?
75
+ - if @product.supplier == settings.supplier && !@product.remote_product.present?
47
76
  = haml "widgets/_link".to_sym, locals: {local_product: @product, redirect_to: 'product'}
48
77
  %br
49
78
  = haml :"_hide_unhide_button", locals: {product: @product}
@@ -81,5 +110,29 @@
81
110
 
82
111
  .pure-u-3-5
83
112
  = haml :"product/_stock_sales_plot", locals: {plot_data: @plot_data, markers: @sales_monthly}
84
- -#%h2 Orders
85
- -#= product.order_items.order ... link
113
+
114
+ %br
115
+
116
+ - if @stock_product.present?
117
+ %h2 Stock and Sales data statistics
118
+ = haml "stock_product/value_table".to_sym, locals: {stock_product: @stock_product}
119
+ %br
120
+
121
+ - if @product.order_items.present?
122
+ %h2 Orders
123
+ %table.pure-table
124
+ %thead
125
+ %tr
126
+ %th Order
127
+ %th Date
128
+ %th Num ordered
129
+ %th Num stocked
130
+ %tbody
131
+ - @product.order_items.where("num_ordered > 0").order(updated_at: :desc).find_each do |order_item|
132
+ %tr
133
+ %td= order_link order_item.order
134
+ %td= order_item.order.updated_at
135
+ %td= order_item.num_ordered
136
+ %td= order_item.num_stocked
137
+
138
+
@@ -5,7 +5,7 @@
5
5
  #modal-plot.modal-plot
6
6
 
7
7
  :javascript
8
- $(function() {
8
+ $(document).ready(function() {
9
9
  $( "#tabs" ).tabs();
10
10
  });
11
11
 
@@ -1,13 +1,17 @@
1
- %table.pure-table
1
+ %table.pure-table.pure-table-striped
2
2
  %thead
3
3
  %tr
4
4
  %th
5
+ = product_icon
5
6
  Product name
6
7
  %th
7
8
  Product ID
8
9
  %th
10
+ = supplier_icon
9
11
  Supplier
10
12
  %th
13
+ = stock_icon
14
+ = sales_icon
11
15
  Stock/ Sales
12
16
  %tbody
13
17
  - products.each do |product|
@@ -8,12 +8,16 @@
8
8
  %thead
9
9
  %tr
10
10
  %th
11
+ = product_icon
11
12
  Product
12
13
  %th
13
14
  Local Name
14
15
  %th
15
16
  Quantity
16
17
  %tbody
18
+ - if @cart_products.empty?
19
+ %tr
20
+ %td(colspan=3) Remote Cart empty
17
21
  - @cart_products.each do |product, qty|
18
22
  - if product.nil?
19
23
  %tr
@@ -28,3 +32,9 @@
28
32
  = local_product_link(product.local_product) rescue "unlinked"
29
33
  %td
30
34
  = qty
35
+ %br
36
+ %br
37
+ %a(href="#{Rawbotz::RemoteShop::cart_page_url settings.conf}" target="remote_shop")
38
+ = view_icon
39
+ = external_link_icon
40
+ View Remote Cart
@@ -13,9 +13,11 @@ ID #{@remote_order_id}
13
13
  %th Local Name
14
14
  %th Qty
15
15
  %th Refund
16
- %th Shelve
16
+ %th
17
+ = shelve_icon
18
+ Shelve
17
19
  %tbody
18
- - @remote_products_qty.sort_by{|p,_| p.name}.each do |p, q|
20
+ - @remote_products_qty.sort_by{|p,_| p.name}.each do |p, qty, refunded|
19
21
  %tr
20
22
  %td
21
23
  = remote_product_link p
@@ -28,8 +30,8 @@ ID #{@remote_order_id}
28
30
  Link (broken)
29
31
  -else
30
32
  not in database
31
- %td=q
32
- %td
33
+ %td=qty
34
+ %td=refunded
33
35
  %td
34
36
  -if shelve = p.local_product.try(:shelve_nr)
35
37
  = shelve
@@ -4,17 +4,20 @@
4
4
 
5
5
  %center
6
6
  %table.pure-table.pure-table-striped
7
- %tr
8
- %th Date
9
- %th Volume
10
- %th Action
11
- - @last_orders.each do |p|
7
+ %thead
12
8
  %tr
13
- %td=p[0]
14
- %td=p[1]
15
- %td
16
- %a(href="#{p[2]}")
17
- Visit remote shop
18
- %br
19
- %a(href="/remote_order/#{p[2][/\d+/]}")
20
- View
9
+ %th Date
10
+ %th Volume
11
+ %th Action
12
+ %tbody
13
+ - @last_orders.each do |p|
14
+ %tr
15
+ %td=p[0]
16
+ %td=p[1]
17
+ %td
18
+ %a(href="#{p[2]}")
19
+ Visit remote shop
20
+ %br
21
+ %a(href="/remote_order/#{p[2][/\d+/]}")
22
+ = view_icon
23
+ View
@@ -0,0 +1,119 @@
1
+ = haml "stock/menu".to_sym
2
+
3
+ :javascript
4
+ $( function() {
5
+ $( document ).tooltip();
6
+ });
7
+
8
+ #modal-plot.modal-plot
9
+
10
+ - if !@wrongly_out_of_stocks.nil? && !@wrongly_out_of_stocks.empty?
11
+ %h2 Products with stock which are set 'not in stock'
12
+ = haml "products/table".to_sym, locals: {products: @wrongly_out_of_stocks}
13
+
14
+
15
+
16
+ %h2 Stock/Sales Statistics
17
+
18
+ Where stock does not last for 10 days.
19
+
20
+ - @suppliers.find_each do |supplier|
21
+ %h3
22
+ = supplier_icon
23
+ = supplier.name
24
+
25
+ - if supplier.minimum_order_value.present?
26
+ %small
27
+ Minimum Order Value: #{supplier.minimum_order_value}
28
+ %br
29
+ - if supplier.delivery_time_days.present?
30
+ %small
31
+ Deliver time in days: #{supplier.delivery_time_days}
32
+ %br
33
+
34
+ %table.pure-table.pure-table-striped
35
+ - predicted_stock_title = "Predicted stock duration (days)"
36
+ - avg_30_title = "Average sales per 30 days, based on sales in last 30 days, corrected by days where product was out of stock"
37
+ - avg_60_title = "Average sales per 30 days, based on sales in last 60 days, corrected by days where product was out of stock"
38
+ - avg_90_title = "Average sales per 30 days, based on sales in last 90 days, corrected by days where product was out of stock"
39
+ - avg_356_title = "Average sales per 30 days, based on sales in last 365 days, corrected by days where product was out of stock"
40
+ %thead
41
+ %tr
42
+ %th Name
43
+ %th(title="Current Stock")
44
+ = stock_icon
45
+ %th(title="#{predicted_stock_title} based on last 30 days sales")
46
+ = stock_empty_icon
47
+ %th(title=avg_30_title)
48
+ = sales_icon
49
+ 30
50
+ %th(title=avg_60_title)
51
+ = sales_icon
52
+ 60
53
+ %th(title=avg_90_title)
54
+ = sales_icon
55
+ 90
56
+ %th(title=avg_90_title)
57
+ = sales_icon
58
+ 356
59
+ %th
60
+ Notes
61
+ %tbody
62
+ - suppliers_stock_product = @stock_products.select{|s|s.product.supplier == supplier}
63
+ - if suppliers_stock_product.empty?
64
+ %tr
65
+ %td(colspan=6)
66
+ Nothing to see here
67
+ - suppliers_stock_product.sort_by{|s| s.expected_stock_lifetime}.each do |p|
68
+ %tr
69
+ - stock_warn = info_icon tooltip_text: "Not enough stock data (first stock record #{p.days_since_first_stock_date.to_i} days ago)!"
70
+ - sales_warn = info_icon tooltip_text: "Not enough sales data (first sale #{p.num_days_first_sale.to_i} days ago)!"
71
+ %td
72
+ = product_link p.product
73
+ %td(title="Current Stock")
74
+ = p.current_stock
75
+ %td(title="#{predicted_stock_title} based on last #{p.sales_per_day_base} days sales")
76
+ = friendly_float p.expected_stock_lifetime
77
+ %td(title=avg_30_title)
78
+ - title = "Average corrected sales, based on last %d days. Sales: %s - Days out of stock: %d" % [30, p.real_sales(30), p.out_of_stock_days(30)]
79
+ %div(title="#{title}")
80
+ = friendly_float(p.corrected_sales(30)) || "?"
81
+ - if p.days_since_first_stock_date < 30
82
+ = stock_warn
83
+ - if p.num_days_first_sale < 30
84
+ = sales_warn
85
+ %td
86
+ %div(title="Average corrected sales, based on last 60 days. Sales: #{p.sales_last_60} - Days out of stock: #{p.out_of_stock_days 60}")
87
+ = friendly_float(p.corrected_sales(60, per_days: 30))
88
+ -#= "%.2f" % (p.corrected_sales_last_60 / 2.0)
89
+ - if p.days_since_first_stock_date < 60
90
+ = stock_warn
91
+ - if p.num_days_first_sale < 60
92
+ = sales_warn
93
+ %td
94
+ %div(title="Average corrected sales, based on last 90 days. Sales: #{p.sales_last_90} - Days out of stock: #{p.out_of_stock_days 90}")
95
+ = friendly_float(p.corrected_sales(90, per_days: 30))
96
+ -#= "%.2f" % (p.corrected_sales_last_90 / 3.0)
97
+ - if p.days_since_first_stock_date < 90
98
+ = stock_warn
99
+ - if p.num_days_first_sale < 90
100
+ = sales_warn
101
+ %td
102
+ %div(title="Average corrected sales, based on last 365 days. Sales: #{p.sales_last_365} - Days out of stock: #{p.out_of_stock_days 365}")
103
+ = friendly_float(p.corrected_sales(365, per_days: 30))
104
+ -#= "%.2f" % (p.corrected_sales_last_365 / 365.0 * 30.0)
105
+ - if p.days_since_first_stock_date < 365
106
+ = stock_warn
107
+ - if p.num_days_first_sale < 365
108
+ = sales_warn
109
+ %td
110
+ - if p.num_days_first_sale.to_i < 10
111
+ New Product! (First sale #{p.num_days_first_sale.to_i} days ago)
112
+ - if p.days_since_first_stock_date.to_i < 30
113
+ Not enough stock data (first stock recorded by rawbotz is #{p.days_since_first_stock_date.to_i} days ago)
114
+
115
+ %br
116
+ %center
117
+ %a.pure-button.pure-button-primary(href="/order/non_remote/#{supplier.id}/new")
118
+ Make an order for #{supplier.name}
119
+ %hr
@@ -0,0 +1,20 @@
1
+ .icon#headicon
2
+ = stock_icon
3
+
4
+ .pure-u-1
5
+ .pure-menu.pure-menu-horizontal#submenu
6
+ %small
7
+ %center
8
+ %ul.pure-menu-list
9
+ %li.pure-menu-item
10
+ %a.pure-menu-link(href="/stock")
11
+ = index_icon
12
+ Stock and Sales
13
+ %li.pure-menu-item
14
+ %a.pure-menu-link(href="/stock/alerts")
15
+ = error_icon
16
+ Alerts
17
+ %li.pure-menu-item
18
+ %a.pure-menu-link(href="/stock/warnings")
19
+ = warning_icon
20
+ Warnings
@@ -0,0 +1,22 @@
1
+ - if stock_product.days_since_first_stock_date.to_i < num_days
2
+ - warn = warning_icon(tooltip_text: "First stock value is only #{stock_product.days_since_first_stock_date.to_i} days ago!")
3
+ - else
4
+ - warn = ""
5
+
6
+ %tr
7
+ %td
8
+ = num_days
9
+ %td
10
+ - if stock_product.num_days_first_sale.to_i < num_days
11
+ = warning_icon tooltip_text: "First sale only #{stock_product.num_days_first_sale.to_i} days ago!"
12
+ = stock_product.real_sales num_days
13
+ %td
14
+ = warn
15
+ = stock_product.out_of_stock_days num_days
16
+ %td
17
+ = warn
18
+ = friendly_float stock_product.corrected_sales num_days
19
+ %td
20
+ = warn
21
+ = friendly_float stock_product.corrected_sales(num_days, per_days: 1)
22
+
@@ -0,0 +1,28 @@
1
+ %table.pure-table.pure-table-striped
2
+ %thead
3
+ %tr
4
+ %th Number of days
5
+ %th Sales
6
+ %th Days out of stock
7
+ %th Corrected sales
8
+ %th Corrected sales per day
9
+ %tbody
10
+ - [30, 60, 90, 365].each do |num_days|
11
+ = haml "stock_product/_value_table_line".to_sym,
12
+ locals: {stock_product: stock_product, num_days: num_days}
13
+ %dl
14
+ %dt
15
+ Number of days since first sale
16
+ %dd
17
+ = stock_product.num_days_first_sale.to_i
18
+ %dt
19
+ Number of days since first stock entry
20
+ %dd
21
+ = stock_product.days_since_first_stock_date.to_i
22
+
23
+ -#%h3 Sales Prediction
24
+ -#.pure-u-1-1
25
+ -# %h2 Stock
26
+ -# %h4 First registered stock
27
+ -# -#= stock_product.days_since_first_stock
28
+
@@ -0,0 +1,157 @@
1
+ :javascript
2
+ $( function() {
3
+ $( document ).tooltip();
4
+ });
5
+
6
+ %h1 Stockexplorer supplier #{@supplier.name}
7
+
8
+ #supplier_info
9
+ - if @supplier.order_info.present?
10
+ #flash.ui-state-highlight
11
+ = info_icon
12
+ %b Delivery info:
13
+ = @supplier.order_info
14
+
15
+ - if @supplier.delivery_time_days
16
+ #flash.ui-state-highlight
17
+ = info_icon
18
+ %b Delivery Time (in days):
19
+ = @supplier.delivery_time_days
20
+
21
+ - if @supplier.minimum_order_value
22
+ #flash.ui-state-highlight
23
+ = info_icon
24
+ %b Minimum Order Value
25
+ = @supplier.minimum_order_value
26
+
27
+
28
+ - if @supplier.order_info.present? || @supplier.delivery_time_days || @supplier.minimum_order_value
29
+ %br
30
+
31
+ %center
32
+ %table.pure-table.pure-table-striped
33
+ %thead
34
+ %tr
35
+ %th
36
+ %th
37
+ %th
38
+ %th.left-bordered(colspan=2)
39
+ %center
40
+ 30 days
41
+ %th.left-bordered(colspan=3)
42
+ %center
43
+ 60 days
44
+ %th.left-bordered(colspan=3)
45
+ %center
46
+ 90 days
47
+ %th.left-bordered(colspan=3)
48
+ %center
49
+ 356 days
50
+ %th.left-bordered
51
+ %th
52
+ %th
53
+ %tr
54
+ %th Name
55
+ %th(title="Packsize")
56
+ = packsize_icon
57
+ %th(title="Current Stock")
58
+ = stock_icon
59
+ %th.left-bordered(title="Sales in the last 30 days")
60
+ = sales_icon
61
+ %th(title="Days where Product was unavailable (out of stock) in the last 30 days")
62
+ %span.fa-stack
63
+ %i.fa.fa-shopping-cart.fa-stack-1x
64
+ %i.fa.fa-ban.fa-stack-2x.text-danger
65
+ %th.left-bordered(title="Sales in the last 60 days")
66
+ = sales_icon
67
+ %th(title="Days where Product was unavailable (out of stock) in the last 60 days")
68
+ %span.fa-stack
69
+ %i.fa.fa-shopping-cart.fa-stack-1x
70
+ %i.fa.fa-ban.fa-stack-2x.text-danger
71
+ %th(title="The 30 days average sales looking at 60 days. The second value equals takes in account the days in which the product was not available.)")
72
+ average / cleaned
73
+ %th.left-bordered(title="Sales in the last 90 days")
74
+ = sales_icon
75
+ %th(title="Days where Product was unavailable (out of stock) in the last 90 days")
76
+ %span.fa-stack
77
+ %i.fa.fa-shopping-cart.fa-stack-1x
78
+ %i.fa.fa-ban.fa-stack-2x.text-danger
79
+ %th(title="The 30 days average sales looking at 90 days. The second value equals takes in account the days in which the product was not available.)")
80
+ average / cleaned
81
+ %th.left-bordered(title="Sales in the last 356 days")
82
+ = sales_icon
83
+ %th(title="Days where Product was unavailable (out of stock) in the last 356 days")
84
+ %span.fa-stack
85
+ %i.fa.fa-shopping-cart.fa-stack-1x
86
+ %i.fa.fa-ban.fa-stack-2x.text-danger
87
+ %th(title="The 356 days average sales looking at 90 days. The second value equals takes in account the days in which the product was not available.)")
88
+ average / cleaned
89
+ %th.left-bordered Missing
90
+ %th Purchase Price
91
+ %th Chart
92
+ %tbody
93
+ - @supplier.local_products.find_each do |product|
94
+ %tr
95
+ %td(title="Product Name")
96
+ = product_link product
97
+ - if product.supplier_prod_name
98
+ %br
99
+ %small
100
+ = product.supplier_sku
101
+ = product.supplier_prod_name
102
+ - if product.order_info.present?
103
+ #flash.ui-state-highlight
104
+ = error_icon
105
+ = product.order_info
106
+ %td(title="Product Packsize")
107
+ - if product.packsize.present?
108
+ = product.packsize
109
+ - else
110
+ %i.fa.fa-ban
111
+ %td(title="Product Stock (current)")
112
+ = @stock[product.product_id]
113
+ %td.left-bordered(title="Sales in last 30 days")
114
+ = @sales_30[product.product_id].qty
115
+ %td(title="Number of days where product was out of stock in the last 30 days")
116
+ = @out_of_stock_days_30[product.product_id]
117
+ - if product.stock_items.present? && (Date.today - product.stock_items.order(created_at: :asc).first.created_at.to_date).to_i < 30
118
+ .stock_warning(title="Warning, first stock for this product is from #{product.stock_items.order(created_at: :asc).first.created_at}")
119
+ = error_icon
120
+ %td.left-bordered(title="Sales in the last 60 days")
121
+ = @sales_60[product.product_id].qty
122
+ %td
123
+ = @out_of_stock_days_60[product.product_id]
124
+ %td
125
+ = (@sales_60[product.product_id].qty.to_f / 2.0).to_i
126
+ \/
127
+ = (@sales_60[product.product_id].qty.to_f / (60 - @out_of_stock_days_60[product.product_id]) * 30).to_i
128
+ %td.left-bordered(title="Sales in the last 90 days")
129
+ = @sales_90[product.product_id].qty
130
+ %td
131
+ = @out_of_stock_days_90[product.product_id]
132
+ %td
133
+ = (@sales_90[product.product_id].qty.to_f / 3.0).to_i
134
+ \/
135
+ = (@sales_90[product.product_id].qty.to_f / (90 - @out_of_stock_days_90[product.product_id]) * 30).to_i
136
+ %td.left-bordered
137
+ = @sales_356[product.product_id].qty
138
+ %td
139
+ = @out_of_stock_days_356[product.product_id]
140
+ %td
141
+ = (@sales_356[product.product_id].qty.to_f / 11.86).to_i
142
+ \/
143
+ = (@sales_356[product.product_id].qty.to_f / (356 - @out_of_stock_days_356[product.product_id]) * 30).to_i
144
+ -#%td
145
+ -# - if product_stock && product_monthly_sales
146
+ -# -# red/yellow/green
147
+ -# -# if negative, put button
148
+ -# = product_stock - product_monthly_sales
149
+ %td.left-bordered
150
+ %td
151
+ - if product.purchase_price
152
+ = product.purchase_price
153
+
154
+ %td
155
+ - stock_url = "/product/#{product.id}/stock_sales_plot"
156
+ %a.stock_show_action{:href => "", :data => {url: stock_url, product: product.name}}
157
+ Stock/Sales