vyapari 0.1.4 → 0.1.5dev

Sign up to get free protection for your applications and to get access to all the features.
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