vyapari 0.1.4 → 0.1.5dev

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 (164) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/vyapari/sample_stock_bundle.csv +1 -0
  3. data/app/controllers/vyapari/admin/base_controller.rb +10 -0
  4. data/app/controllers/vyapari/admin/brands_controller.rb +99 -0
  5. data/app/controllers/vyapari/admin/categories_controller.rb +115 -0
  6. data/app/controllers/vyapari/admin/countries_controller.rb +2 -2
  7. data/app/controllers/vyapari/admin/dashboard_controller.rb +3 -1
  8. data/app/controllers/vyapari/admin/exchange_rates_controller.rb +2 -2
  9. data/app/controllers/vyapari/admin/products_controller.rb +79 -0
  10. data/app/controllers/vyapari/admin/regions_controller.rb +1 -1
  11. data/app/controllers/vyapari/admin/resource_controller.rb +1 -0
  12. data/app/controllers/vyapari/admin/stores_controller.rb +67 -0
  13. data/app/controllers/vyapari/admin/suppliers_controller.rb +67 -0
  14. data/app/controllers/vyapari/admin/terminals_controller.rb +150 -0
  15. data/app/controllers/vyapari/application_controller.rb +12 -0
  16. data/app/controllers/vyapari/store_manager/base_controller.rb +28 -0
  17. data/app/controllers/vyapari/store_manager/dashboard_controller.rb +30 -0
  18. data/app/controllers/vyapari/store_manager/resource_controller.rb +17 -0
  19. data/app/controllers/vyapari/store_manager/stock_bundles_controller.rb +206 -0
  20. data/app/controllers/vyapari/store_manager/stock_entries_controller.rb +161 -0
  21. data/app/controllers/vyapari/terminal_staff/base_controller.rb +29 -0
  22. data/app/controllers/vyapari/terminal_staff/dashboard_controller.rb +29 -0
  23. data/app/controllers/vyapari/terminal_staff/invoices_controller.rb +138 -0
  24. data/app/controllers/vyapari/terminal_staff/line_items_controller.rb +123 -0
  25. data/app/controllers/vyapari/terminal_staff/resource_controller.rb +17 -0
  26. data/app/controllers/vyapari/user_dashboard_controller.rb +31 -0
  27. data/app/models/brand.rb +63 -10
  28. data/app/models/category.rb +60 -16
  29. data/app/models/country.rb +27 -5
  30. data/app/models/exchange_rate.rb +31 -6
  31. data/app/models/image/brand_image.rb +3 -0
  32. data/app/models/image/category_image.rb +3 -0
  33. data/app/models/image/product_image.rb +3 -0
  34. data/app/models/invoice.rb +223 -0
  35. data/app/models/line_item.rb +206 -0
  36. data/app/models/product.rb +67 -13
  37. data/app/models/region.rb +26 -3
  38. data/app/models/stock_bundle.rb +249 -0
  39. data/app/models/stock_entry.rb +271 -0
  40. data/app/models/store.rb +216 -0
  41. data/app/models/supplier.rb +85 -0
  42. data/app/models/terminal.rb +158 -0
  43. data/app/models/vyapari/application_record.rb +4 -0
  44. data/app/uploaders/brand_image_uploader.rb +14 -0
  45. data/app/uploaders/category_image_uploader.rb +14 -0
  46. data/app/uploaders/product_image_uploader.rb +14 -0
  47. data/app/uploaders/stock_bundle_uploader.rb +10 -0
  48. data/app/views/layouts/kuppayam/_footer.html.erb +1 -1
  49. data/app/views/layouts/kuppayam/_sidebar.html.erb +45 -44
  50. data/app/views/layouts/vyapari/_store_manager_menu.html.erb +107 -0
  51. data/app/views/layouts/vyapari/_terminal_staff_menu.html.erb +103 -0
  52. data/app/views/layouts/vyapari/store_manager.html.erb +112 -0
  53. data/app/views/layouts/vyapari/terminal_staff.html.erb +116 -0
  54. data/app/views/vyapari/admin/brands/_form.html.erb +23 -0
  55. data/app/views/vyapari/admin/brands/_index.html.erb +89 -0
  56. data/app/views/vyapari/admin/brands/_row.html.erb +63 -0
  57. data/app/views/vyapari/admin/brands/_show.html.erb +104 -0
  58. data/app/views/vyapari/admin/brands/index.html.erb +48 -0
  59. data/app/views/vyapari/admin/categories/_form.html.erb +28 -0
  60. data/app/views/vyapari/admin/categories/_index.html.erb +101 -0
  61. data/app/views/vyapari/admin/categories/_row.html.erb +69 -0
  62. data/app/views/vyapari/admin/categories/_show.html.erb +115 -0
  63. data/app/views/vyapari/admin/{users → categories}/index.html.erb +8 -24
  64. data/app/views/vyapari/admin/countries/_index.html.erb +1 -1
  65. data/app/views/vyapari/admin/countries/index.html.erb +19 -3
  66. data/app/views/vyapari/admin/exchange_rates/_form.html.erb +3 -4
  67. data/app/views/vyapari/admin/exchange_rates/_index.html.erb +7 -7
  68. data/app/views/vyapari/admin/exchange_rates/_row.html.erb +3 -3
  69. data/app/views/vyapari/admin/exchange_rates/_show.html.erb +1 -0
  70. data/app/views/vyapari/admin/exchange_rates/index.html.erb +19 -3
  71. data/app/views/vyapari/admin/products/_form.html.erb +32 -0
  72. data/app/views/vyapari/admin/products/_index.html.erb +58 -0
  73. data/app/views/vyapari/admin/products/_row.html.erb +30 -0
  74. data/app/views/vyapari/admin/products/_show.html.erb +81 -0
  75. data/app/views/vyapari/admin/products/index.html.erb +48 -0
  76. data/app/views/vyapari/admin/regions/_index.html.erb +1 -1
  77. data/app/views/vyapari/admin/regions/index.html.erb +19 -3
  78. data/app/views/vyapari/admin/stores/_form.html.erb +37 -0
  79. data/app/views/vyapari/admin/stores/_index.html.erb +84 -0
  80. data/app/views/vyapari/admin/stores/_row.html.erb +55 -0
  81. data/app/views/vyapari/admin/stores/_show.html.erb +110 -0
  82. data/app/views/vyapari/admin/stores/index.html.erb +48 -0
  83. data/app/views/vyapari/admin/suppliers/_form.html.erb +32 -0
  84. data/app/views/vyapari/admin/suppliers/_index.html.erb +58 -0
  85. data/app/views/vyapari/admin/suppliers/_row.html.erb +30 -0
  86. data/app/views/vyapari/admin/suppliers/_show.html.erb +81 -0
  87. data/app/views/vyapari/admin/suppliers/index.html.erb +48 -0
  88. data/app/views/vyapari/admin/terminals/_form.html.erb +24 -0
  89. data/app/views/vyapari/admin/terminals/_index.html.erb +75 -0
  90. data/app/views/vyapari/admin/terminals/_row.html.erb +49 -0
  91. data/app/views/vyapari/admin/terminals/_show.html.erb +74 -0
  92. data/app/views/vyapari/store_manager/dashboard/index.html.erb +93 -0
  93. data/app/views/vyapari/store_manager/stock_bundles/_form.html.erb +99 -0
  94. data/app/views/vyapari/store_manager/stock_bundles/_index.html.erb +74 -0
  95. data/app/views/vyapari/store_manager/stock_bundles/_row.html.erb +44 -0
  96. data/app/views/vyapari/store_manager/stock_bundles/_show.html.erb +110 -0
  97. data/app/views/vyapari/store_manager/stock_bundles/create.html.erb +57 -0
  98. data/app/views/vyapari/store_manager/stock_bundles/index.html.erb +36 -0
  99. data/app/views/vyapari/store_manager/stock_bundles/update.html.erb +57 -0
  100. data/app/views/vyapari/store_manager/stock_entries/_form.html.erb +50 -0
  101. data/app/views/vyapari/store_manager/stock_entries/_index.html.erb +80 -0
  102. data/app/views/vyapari/store_manager/stock_entries/_row.html.erb +33 -0
  103. data/app/views/vyapari/store_manager/stock_entries/_show.html.erb +110 -0
  104. data/app/views/vyapari/store_manager/stock_entries/_stock_bundle.html.erb +61 -0
  105. data/app/views/vyapari/store_manager/stock_entries/index.html.erb +45 -0
  106. data/app/views/vyapari/terminal_staff/dashboard/_counts.html.erb +88 -0
  107. data/app/views/vyapari/terminal_staff/dashboard/_invoices.html.erb +37 -0
  108. data/app/views/vyapari/terminal_staff/dashboard/index.html.erb +36 -0
  109. data/app/views/vyapari/terminal_staff/invoices/_draft.html.erb +62 -0
  110. data/app/views/vyapari/terminal_staff/invoices/_form.html.erb +120 -0
  111. data/app/views/vyapari/terminal_staff/invoices/_index.html.erb +64 -0
  112. data/app/views/vyapari/terminal_staff/invoices/_row.html.erb +33 -0
  113. data/app/views/vyapari/terminal_staff/invoices/_show.html.erb +171 -0
  114. data/app/views/vyapari/terminal_staff/invoices/index.html.erb +37 -0
  115. data/app/views/vyapari/terminal_staff/invoices/new.js.erb +13 -0
  116. data/app/views/vyapari/terminal_staff/invoices/show.html.erb +1 -0
  117. data/app/views/vyapari/terminal_staff/line_items/_form.html.erb +40 -0
  118. data/app/views/vyapari/terminal_staff/line_items/_index.html.erb +94 -0
  119. data/app/views/vyapari/terminal_staff/line_items/create.js.erb +34 -0
  120. data/app/views/vyapari/terminal_staff/line_items/destroy.js.erb +25 -0
  121. data/app/views/vyapari/terminal_staff/stores/index.html.erb +24 -0
  122. data/app/views/vyapari/user_dashboard/index.html.erb +51 -0
  123. data/config/routes.rb +62 -5
  124. data/db/import_data/brands.csv +7 -0
  125. data/db/import_data/categories.csv +12 -0
  126. data/db/import_data/countries.csv +1 -0
  127. data/db/import_data/dummy/brands.csv +7 -0
  128. data/db/import_data/dummy/categories.csv +12 -0
  129. data/db/import_data/dummy/countries.csv +1 -0
  130. data/db/import_data/dummy/exchange_rates.csv +5 -0
  131. data/db/import_data/dummy/products-copy.csv +1 -0
  132. data/db/import_data/dummy/products.csv +1 -0
  133. data/db/import_data/dummy/products.xlsx +0 -0
  134. data/db/import_data/dummy/regions.csv +13 -0
  135. data/db/import_data/dummy/stores.csv +10 -0
  136. data/db/import_data/dummy/suppliers.csv +14 -0
  137. data/db/import_data/dummy/terminals.csv +11 -0
  138. data/db/import_data/exchange_rates.csv +5 -0
  139. data/db/import_data/regions.csv +13 -0
  140. data/db/import_data/stores.csv +3 -0
  141. data/db/import_data/suppliers.csv +14 -0
  142. data/db/import_data/terminals.csv +3 -0
  143. data/db/migrate/20170000000200_create_exchange_rates.rb +3 -2
  144. data/db/migrate/20170000000203_create_contacts.rb +22 -0
  145. data/db/migrate/20170000000204_create_bank_accounts.rb +21 -0
  146. data/db/migrate/20170000000205_create_suppliers.rb +18 -0
  147. data/db/migrate/20170000000206_create_stores.rb +21 -0
  148. data/db/migrate/20170000000207_create_terminals.rb +18 -0
  149. data/db/migrate/20170000000210_create_brands.rb +14 -0
  150. data/db/migrate/20170000000211_create_categories.rb +22 -0
  151. data/db/migrate/20170000000212_create_products.rb +29 -0
  152. data/db/migrate/20170000000213_create_invoices.rb +58 -0
  153. data/db/migrate/20170000000215_create_stock_bundles.rb +17 -0
  154. data/db/migrate/20170000000216_create_stock_entries.rb +20 -0
  155. data/db/sample_reports/products.xlsx +0 -0
  156. data/lib/tasks/vyapari/all.rake +73 -0
  157. data/lib/vyapari/version.rb +1 -1
  158. metadata +150 -15
  159. data/app/controllers/vyapari/admin/users_controller.rb +0 -130
  160. data/app/views/vyapari/admin/users/_form.html.erb +0 -39
  161. data/app/views/vyapari/admin/users/_index.html.erb +0 -101
  162. data/app/views/vyapari/admin/users/_row.html.erb +0 -72
  163. data/app/views/vyapari/admin/users/_show.html.erb +0 -199
  164. data/lib/tasks/vyapari_tasks.rake +0 -4
@@ -0,0 +1,249 @@
1
+ require 'csv'
2
+
3
+ class StockBundle < ActiveRecord::Base
4
+
5
+ # Constants
6
+ PENDING = "pending" # Default Status
7
+ ERRORED = "errored"
8
+ APPROVED = "approved"
9
+
10
+ STATUS_HASH = {"Pending" => PENDING, "Approved" => APPROVED, "Errored" => ERRORED}
11
+ STATUS_HASH_REVERSE = {PENDING => "Pending", APPROVED => "Approved", ERRORED => "Errored"}
12
+
13
+ # Validations
14
+ validates :name, :presence=> true, uniqueness: true
15
+ validates :uploaded_date, presence: true
16
+ validates :status, :presence=> true, :inclusion => {:in => STATUS_HASH_REVERSE.keys, :presence_of => :status, :message => "%{value} is not a valid status" }
17
+ # validates :file, :presence=> true
18
+
19
+ # Associations
20
+ has_many :stock_entries
21
+ belongs_to :uploader, class_name: 'User'
22
+ belongs_to :supplier, optional: true
23
+ belongs_to :store
24
+
25
+ # Uploader
26
+ mount_uploader :file, File::StockBundleUploader
27
+ mount_uploader :error_file, File::StockBundleUploader
28
+
29
+ # ------------------
30
+ # Class Methods
31
+ # ------------------
32
+
33
+ # return an active record relation object with the search query in its where clause
34
+ # Return the ActiveRecord::Relation object
35
+ # == Examples
36
+ # >>> obj.search(query)
37
+ # => ActiveRecord::Relation object
38
+ scope :search, lambda {|query| joins(:supplier, :store).where("LOWER(suppliers.name) LIKE LOWER('%#{query}%') OR LOWER(stores.name) LIKE LOWER('%#{query}%')")}
39
+
40
+ scope :status, lambda { |status| where ("LOWER(stock_bundles.status)='#{status}'") }
41
+
42
+ scope :pending, -> { where(status: PENDING) }
43
+ scope :approved, -> { where(status: APPROVED) }
44
+
45
+ # ------------------
46
+ # Class Methods
47
+ # ------------------
48
+
49
+ def parse_stocks
50
+
51
+ # For some reasn it throws error for self.error_details unless we reload
52
+ self.reload
53
+
54
+ path = "#{Rails.root}/public#{self.file.url}"
55
+ begin
56
+ csv_table = CSV.table(path, {headers: true, converters: nil, header_converters: :symbol})
57
+ rescue CSV::MalformedCSVError => e
58
+ self.error_summary = "The Uploaded File is corrupted."
59
+ self.error_details = "#{e.class}: #{e.message}"
60
+ self.save
61
+ puts self.error_summary.red
62
+ puts self.error_details.red
63
+ return false
64
+ rescue Exception => e
65
+ self.error_summary = "The Uploaded File format is not supported."
66
+ self.error_details = "#{e.class}: #{e.message}"
67
+ puts self.error_summary.red
68
+ puts self.error_details.red
69
+ self.save
70
+ return false
71
+ end
72
+
73
+ headers = csv_table.headers
74
+
75
+ StockEntry.where(stock_bundle: self.id).destroy_all
76
+
77
+ # We need a collection of all the column headings to pass to error hander to reproduce the errors in same format
78
+ columns = [:env_sku, :name, :reference_number, :one_liner, :description, :purchased_price, :landed_price, :selling_price, :retail_price, :brand, :category, :quantity]
79
+
80
+ # Initializing the Data Error to store errors for each column
81
+ data_error = Kuppayam::Importer::DataError.new
82
+ data_error.columns = columns
83
+
84
+ csv_table.each_with_index do |row, i|
85
+
86
+ row.headers.each{ |cell| row[cell] = row[cell].to_s.strip }
87
+
88
+ if row[:ean_sku].blank?
89
+ data_error.add_column_error(:ean_sku, "", "ENV / SKU number is blank", i)
90
+ next
91
+ end
92
+
93
+ if row[:quantity].blank?
94
+ data_error.add_column_error(:quantity, "", "Quantity is blank", i)
95
+ next
96
+ end
97
+
98
+ product = Product.where("ean_sku = ?", row[:ean_sku]).first || Product.new
99
+
100
+ product.ean_sku = row[:ean_sku]
101
+ product.name = row[:name]
102
+ product.reference_number = row[:reference_number]
103
+ product.one_liner = row[:one_liner]
104
+ product.description = row[:description]
105
+
106
+ product.purchased_price = row[:purchased_price]
107
+ product.landed_price = row[:landed_price]
108
+ product.selling_price = row[:selling_price]
109
+ product.retail_price = row[:retail_price]
110
+
111
+ product.purchased_price = 0.00 if product.purchased_price.blank?
112
+ product.landed_price = 0.00 if product.landed_price.blank?
113
+ product.selling_price = 0.00 if product.selling_price.blank?
114
+ product.retail_price = 0.00 if product.retail_price.blank?
115
+
116
+ product.brand = Brand.where("name = ?", row[:brand]).first || product.build_brand(name: row[:brand]) if row[:brand]
117
+ product.category = Category.where("name = ?", row[:category]).first || product.build_category(name: row[:category]) if row[:category]
118
+
119
+ stock_entry = StockEntry.new()
120
+
121
+ stock_entry.store = self.store
122
+ stock_entry.product = product
123
+ stock_entry.supplier = self.supplier
124
+ stock_entry.quantity = row[:quantity]
125
+ stock_entry.stock_bundle = self
126
+ stock_entry.status = :pending
127
+
128
+ if product.valid? && stock_entry.valid?
129
+ product.save!
130
+ stock_entry.save!
131
+ else
132
+ unless product.valid?
133
+ columns.each do |col_name|
134
+ data_error.add_column_error(col_name, row[col_name], product.errors[col_name], i) if product.errors.has_key?(col_name)
135
+ end
136
+ end
137
+ unless stock_entry.valid?
138
+ columns.each do |col_name|
139
+ data_error.add_column_error(col_name, row[col_name], stock_entry.errors[col_name], i) if stock_entry.errors.has_key?(col_name)
140
+ end
141
+ end
142
+ end
143
+
144
+ end
145
+
146
+ if data_error.errors.any?
147
+ self.error_summary = "There are few errors in some of the rows in the CSV file. Open the error file to know more."
148
+ # self.error_file = data_error.generate_error_file
149
+ end
150
+
151
+ self.save!
152
+ self.stock_entries.update_all(status: :active) if data_error.errors.blank?
153
+
154
+ return data_error.errors.blank?
155
+ end
156
+
157
+ # ------------------
158
+ # Instance Methods
159
+ # ------------------
160
+
161
+ def display_name
162
+ "Stock Bundle - #{self.id} from #{supplier.try(:name)}"
163
+ end
164
+
165
+ def display_status
166
+ STATUS_HASH_REVERSE[self.status]
167
+ end
168
+
169
+ def display_file_name
170
+ if self.file && self.file.file
171
+ self.file.file.filename
172
+ else
173
+ self.display_name
174
+ end
175
+ end
176
+
177
+ def original_file_path
178
+ self.file && self.file.file ? self.file.file.path : nil
179
+ end
180
+
181
+ def original_error_file_path
182
+ self.error_file && self.error_file.file ? self.error_file.file.path : nil
183
+ end
184
+
185
+ # * Return true if the stock_entry is approved, else false.
186
+ # == Examples
187
+ # >>> stock_entry.pending?
188
+ # => true
189
+ def pending?
190
+ (status == PENDING)
191
+ end
192
+
193
+ # change the status of the stock_entry to :pending
194
+ # Return the status
195
+ # == Examples
196
+ # >>> stock_entry.mark_as_pending!
197
+ # => "pending"
198
+ def mark_as_pending!
199
+ self.update_attribute(:status, PENDING)
200
+ self.stock_entries.update_all(status: StockEntry::PENDING)
201
+ end
202
+
203
+ # * Return true if the stock_entry is approved, else false.
204
+ # == Examples
205
+ # >>> stock_entry.approved?
206
+ # => true
207
+ def approved?
208
+ (status == APPROVED)
209
+ end
210
+
211
+ # change the status to :approved
212
+ # Return the status
213
+ # == Examples
214
+ # >>> stock_entry.approve!
215
+ # => "approve"
216
+ def approve!
217
+ self.update_attribute(:status, APPROVED)
218
+ self.stock_entries.update_all(status: StockEntry::ACTIVE)
219
+ true
220
+ end
221
+
222
+ # * Return true if the stock_entry is errored, else false.
223
+ # == Examples
224
+ # >>> stock_entry.mark_as_errored?
225
+ # => true
226
+ def mark_as_errored?
227
+ (status == ERRORED)
228
+ end
229
+
230
+ # change the status to :errored
231
+ # Return the status
232
+ # == Examples
233
+ # >>> stock_entry.mark_as_errored!
234
+ # => "approve"
235
+ def mark_as_errored!
236
+ self.update_attribute(:status, ERRORED)
237
+ self.stock_entries.update_all(status: StockEntry::PENDING)
238
+ true
239
+ end
240
+
241
+ def can_be_deleted?
242
+ true
243
+ end
244
+
245
+ def can_be_edited?
246
+ true
247
+ end
248
+
249
+ end
@@ -0,0 +1,271 @@
1
+ class StockEntry < Vyapari::ApplicationRecord
2
+
3
+ # Constants
4
+ ACTIVE = "active"
5
+ SOLD = "sold"
6
+ DAMAGED = "damaged"
7
+ RECEIVED = "received"
8
+ RETURNED = "returned"
9
+ RESERVED = "reserved"
10
+ PENDING = "pending"
11
+
12
+ STATUS_HASH = {"Active" => ACTIVE, "Sold" => SOLD, "Damaged" => DAMAGED, "Received" => RECEIVED, "Reserved" => RESERVED, "Pending" => PENDING, "Returned" => RETURNED}
13
+ STATUS_HASH_REVERSE = {ACTIVE => "Active", SOLD => "Sold", DAMAGED => "Damaged", RECEIVED => "Received", RESERVED => "Reserved", PENDING => "Pending", RETURNED => "Returned"}
14
+
15
+ # Validations
16
+ validates :store, presence: true
17
+ validates :product, presence: true
18
+ validates :quantity, presence: true, numericality: true
19
+ validates :status, :presence=> true, :inclusion => {:in => STATUS_HASH_REVERSE.keys, :presence_of => :status, :message => "%{value} is not a valid status" }
20
+
21
+ # Associations
22
+ belongs_to :store
23
+ belongs_to :product
24
+ belongs_to :supplier, optional: true
25
+ belongs_to :stock_bundle, optional: true
26
+ belongs_to :invoice, optional: true
27
+
28
+ # ------------------
29
+ # Class Methods
30
+ # ------------------
31
+
32
+ # return an active record relation object with the search query in its where clause
33
+ # Return the ActiveRecord::Relation object
34
+ # == Examples
35
+ # >>> obj.search(query)
36
+ # => ActiveRecord::Relation object
37
+ scope :search, lambda {|query| joins("LEFT JOIN `stores` ON `stores`.`id` = `stock_entries`.`store_id` LEFT JOIN `products` ON `products`.`id` = `stock_entries`.`product_id` LEFT JOIN `suppliers` ON `suppliers`.`id` = `stock_entries`.`supplier_id`").where("LOWER(products.name) LIKE LOWER('%#{query}%') OR
38
+ LOWER(suppliers.name) LIKE LOWER('%#{query}%') OR
39
+ LOWER(products.ean_sku) LIKE LOWER('%#{query}%') OR
40
+ LOWER(products.one_liner) LIKE LOWER('%#{query}%') OR
41
+ LOWER(products.description) LIKE LOWER('%#{query}%') OR
42
+ LOWER(stores.name) LIKE LOWER('%#{query}%')")}
43
+
44
+
45
+ scope :active, -> { where(status: ACTIVE) }
46
+ scope :sold, -> { where(status: SOLD) }
47
+ scope :damaged, -> { where(status: DAMAGED) }
48
+ scope :returned, -> { where(status: RETURNED) }
49
+ scope :received, -> { where(status: RECEIVED) }
50
+ scope :reserved, -> { where(status: RESERVED) }
51
+ scope :in_stock, -> { where(status: [ACTIVE, RECEIVED, RETURNED]) }
52
+
53
+ def self.save_row_data(row)
54
+
55
+ row.headers.each{ |cell| row[cell] = row[cell].to_s.strip }
56
+
57
+ return if row[:ean_sku].blank?
58
+
59
+ # Initializing error hash for displaying all errors altogether
60
+ error_object = Kuppayam::Importer::ErrorHash.new
61
+
62
+ store = Store.find_by_code(row[:stock])
63
+ unless store
64
+ summary = "Store doesn't exist."
65
+ details = "Error! The store with code #{row[:store]} doesn't exists in the database"
66
+ error_object.errors << { summary: summary, details: details }
67
+ return
68
+ end
69
+
70
+ product = Product.find_by_ean_sku(row[:ean_sku]) || Product.new
71
+
72
+ product.name = row[:name]
73
+ product.code = row[:code]
74
+
75
+ if product.valid?
76
+ product.save!
77
+ else
78
+ summary = "Error while saving product: #{product.name}"
79
+ details = "Error! #{product.errors.full_messages.to_sentence}"
80
+ error_object.errors << { summary: summary, details: details }
81
+ end
82
+
83
+
84
+ stock_entry.store = store
85
+ stock_entry.product = product
86
+ stock_entry.quantity = row[:quantity]
87
+
88
+ stock_entry.set_stock_entry_type(row[:stock_entry_type])
89
+
90
+ stock_entry.region = Region.find_by_code(row[:region]) || Country.find_by_name(row[:country])
91
+ stock_entry.country = Country.find_by_code(row[:country]) || Country.find_by_name(row[:country])
92
+
93
+ if stock_entry.valid?
94
+ stock_entry.save!
95
+ else
96
+ summary = "Error while saving stock_entry: #{stock_entry.name}"
97
+ details = "Error! #{stock_entry.errors.full_messages.to_sentence}"
98
+ error_object.errors << { summary: summary, details: details }
99
+ end
100
+ return error_object
101
+ end
102
+
103
+ # ------------------
104
+ # Instance Methods
105
+ # ------------------
106
+
107
+ def display_name
108
+ "Stock from #{self.supplier.try(:name)}"
109
+ end
110
+
111
+ def display_store_type
112
+ STATUS_HASH[self.status]
113
+ end
114
+
115
+ def display_status
116
+ STATUS_HASH_REVERSE[self.status]
117
+ end
118
+
119
+ def slug
120
+ if self.product
121
+ self.product.name.parameterize
122
+ else
123
+ self.id
124
+ end
125
+ end
126
+
127
+ def to_param
128
+ "#{id}-#{slug}"
129
+ end
130
+
131
+ # change the status to :active
132
+ # Return the status
133
+ # == Examples
134
+ # >>> stock_entry.activate!
135
+ # => "active"
136
+ def activate!
137
+ self.update_attribute(:status, ACTIVE)
138
+ end
139
+
140
+ # change the status to :sold
141
+ # Return the status
142
+ # == Examples
143
+ # >>> stock_entry.sell!
144
+ # => "sold"
145
+ def sell!
146
+ self.update_attribute(:status, SOLD)
147
+ end
148
+
149
+ # change the status to :damaged
150
+ # Return the status
151
+ # == Examples
152
+ # >>> stock_entry.mark_as_damaged!
153
+ # => "damaged"
154
+ def mark_as_damaged!
155
+ self.update_attribute(:status, DAMAGED)
156
+ end
157
+
158
+ # change the status to :received
159
+ # Return the status
160
+ # == Examples
161
+ # >>> stock_entry.mark_as_received!
162
+ # => "received"
163
+ def mark_as_received!
164
+ self.update_attribute(:status, RECEIVED)
165
+ end
166
+
167
+ # change the status to :reserved
168
+ # Return the status
169
+ # == Examples
170
+ # >>> stock_entry.reserve!
171
+ # => "reserved"
172
+ def reserve!
173
+ self.update_attribute(:status, RESERVED)
174
+ end
175
+
176
+ # change the status to :returned
177
+ # Return the status
178
+ # == Examples
179
+ # >>> stock_entry.reserve!
180
+ # => "returned"
181
+ def return!
182
+ self.update_attribute(:status, RETURN)
183
+ end
184
+
185
+ # change the status to :pending
186
+ # Return the status
187
+ # == Examples
188
+ # >>> stock_entry.mark_as_pending!
189
+ # => "pending"
190
+ def mark_as_pending!
191
+ self.update_attribute(:status, PENDING)
192
+ end
193
+
194
+ # * Return true if the stock_entry is active, else false.
195
+ # == Examples
196
+ # >>> stock_entry.active?
197
+ # => true
198
+ def active?
199
+ (status == ACTIVE)
200
+ end
201
+
202
+ # * Return true if the stock_entry is sold, else false.
203
+ # == Examples
204
+ # >>> stock_entry.sold?
205
+ # => true
206
+ def sold?
207
+ (status == SOLD)
208
+ end
209
+
210
+ # * Return true if the stock_entry is damaged, else false.
211
+ # == Examples
212
+ # >>> stock_entry.damaged?
213
+ # => true
214
+ def damaged?
215
+ (status == DAMAGED)
216
+ end
217
+
218
+ # * Return true if the stock_entry is received, else false.
219
+ # == Examples
220
+ # >>> stock_entry.received?
221
+ # => true
222
+ def received?
223
+ (status == RECEIVED)
224
+ end
225
+
226
+ # * Return true if the stock_entry is returned, else false.
227
+ # == Examples
228
+ # >>> stock_entry.returned?
229
+ # => true
230
+ def returned?
231
+ (status == RETURNED)
232
+ end
233
+
234
+ # * Return true if the stock_entry is reserved, else false.
235
+ # == Examples
236
+ # >>> stock_entry.reserved?
237
+ # => true
238
+ def reserved?
239
+ (status == RESERVED)
240
+ end
241
+
242
+ # * Return true if the stock_entry is pending, else false.
243
+ # == Examples
244
+ # >>> stock_entry.pending?
245
+ # => true
246
+ def pending?
247
+ (status == PENDING)
248
+ end
249
+
250
+ def can_be_edited?
251
+ true
252
+ end
253
+
254
+ def can_be_deleted?
255
+ # if self.products.any?
256
+ # #self.errors.add(:base, DELETE_MESSAGE)
257
+ # return false
258
+ # else
259
+ # return true
260
+ # end
261
+ return true
262
+ end
263
+
264
+ def report_heading
265
+ rh = []
266
+ rh << self.company.try(:name) if self.company.name
267
+ rh << self.display_name
268
+ rh.join(", ")
269
+ end
270
+
271
+ end