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,223 @@
1
+ class Invoice < Vyapari::ApplicationRecord
2
+
3
+ # Constants
4
+ DRAFT = "draft"
5
+ ACTIVE = "active"
6
+ CANCELLED = "cancelled"
7
+
8
+ CASH = "cash"
9
+ CREDIT = "credit"
10
+ CREDIT_CARD = "credit_card"
11
+ CHEQUE = "cheque"
12
+
13
+ STATUS_HASH = {"Draft" => DRAFT, "Active" => ACTIVE, "Cancelled" => CANCELLED}
14
+ STATUS_HASH_REVERSE = {DRAFT => "Draft", ACTIVE => "Active", CANCELLED => "Cancelled"}
15
+
16
+ # Call backs
17
+ before_save :calculate_total_amount
18
+
19
+ # Validations
20
+ validates :invoice_number, :presence=> true
21
+ validates :invoice_date, :presence=> true
22
+
23
+ validates :status, :presence=> true, :inclusion => {:in => STATUS_HASH_REVERSE.keys, :presence_of => :status, :message => "%{value} is not a valid status" }
24
+
25
+ # Associations
26
+ belongs_to :terminal
27
+ belongs_to :store
28
+ belongs_to :user
29
+ has_many :line_items
30
+ has_many :stock_entries
31
+
32
+ # ------------------
33
+ # Class Methods
34
+ # ------------------
35
+
36
+ # Scopes
37
+
38
+ # return an active record relation object with the search query in its where clause
39
+ # Return the ActiveRecord::Relation object
40
+ # == Examples
41
+ # >>> invoice.search(query)
42
+ # => ActiveRecord::Relation object
43
+ scope :search, lambda { |query| where("LOWER(invoice_number) LIKE LOWER('%#{query}%') OR LOWER(customer_name) LIKE LOWER('%#{query}%') OR LOWER(customer_address) LIKE LOWER('%#{query}%')")
44
+ }
45
+
46
+ scope :status, lambda { |status| where("LOWER(status)='#{status}'") }
47
+
48
+ scope :draft, -> { where(status: DRAFT) }
49
+ scope :active, -> { where(status: ACTIVE) }
50
+ scope :cancelled, -> { where(status: CANCELLED) }
51
+
52
+ scope :this_month, lambda { where("created_at >= ? AND created_at <= ?", Time.zone.now.beginning_of_month, Time.zone.now.end_of_month) }
53
+
54
+ # ------------------
55
+ # Instance Methods
56
+ # ------------------
57
+
58
+ def initialize
59
+ super
60
+ self.discount = 0.00
61
+ self.adjustment = 0.00
62
+ self.money_taken = 0.00
63
+ self.total_amount = 0.00
64
+ end
65
+
66
+ def display_name
67
+ self.invoice_number
68
+ end
69
+
70
+ def display_status
71
+ STATUS_HASH_REVERSE[self.status]
72
+ end
73
+
74
+ def display_payment_method
75
+ self.payment_method.titleize
76
+ end
77
+
78
+ def slug
79
+ self.invoice_number.parameterize
80
+ end
81
+
82
+ def generate_temporary_invoice_number
83
+ self.invoice_number = "#{Time.now.to_i}"
84
+ end
85
+
86
+ def reset_invoice_number
87
+ self.update_attribute(:invoice_number, "#{INV}-#{self.terminal.code}-#{self.id}") if self.draft?
88
+ end
89
+
90
+ def to_param
91
+ "#{id}-#{slug}"
92
+ end
93
+
94
+ # * Return true if the invoice is draft, else false.
95
+ # == Examples
96
+ # >>> invoice.draft?
97
+ # => true
98
+ def draft?
99
+ (status == DRAFT)
100
+ end
101
+
102
+ # change the status to :draft
103
+ # Return the status
104
+ # == Examples
105
+ # >>> invoice.publish!
106
+ # => "draft"
107
+ def draft!
108
+ self.update_attribute(:status, DRAFT)
109
+ end
110
+
111
+ # * Return true if the invoice is active, else false.
112
+ # == Examples
113
+ # >>> invoice.active?
114
+ # => true
115
+ def active?
116
+ (status == ACTIVE)
117
+ end
118
+
119
+ # change the status to :active
120
+ # Return the status
121
+ # == Examples
122
+ # >>> invoice.unpublish!
123
+ # => "active"
124
+ def activate!
125
+ self.update_attributes(status: ACTIVE)
126
+ end
127
+
128
+ # * Return true if the invoice is cancelled, else false.
129
+ # == Examples
130
+ # >>> invoice.cancelled?
131
+ # => true
132
+ def cancelled?
133
+ (status == CANCELLED)
134
+ end
135
+
136
+ # change the status to :cancelled
137
+ # Return the status
138
+ # == Examples
139
+ # >>> invoice.remove!
140
+ # => "cancelled"
141
+ def cancel!
142
+ self.update_attributes(status: CANCELLED, featured: false)
143
+ end
144
+
145
+ # * Return true if the invoice is cash, else false.
146
+ # == Examples
147
+ # >>> invoice.cash?
148
+ # => true
149
+ def cash?
150
+ (payment_method == CASH)
151
+ end
152
+
153
+ # * Return true if the invoice is credit, else false.
154
+ # == Examples
155
+ # >>> invoice.credit?
156
+ # => true
157
+ def credit?
158
+ (payment_method == CREDIT)
159
+ end
160
+
161
+ # * Return true if the invoice is credit_card, else false.
162
+ # == Examples
163
+ # >>> invoice.credit_card?
164
+ # => true
165
+ def credit_card?
166
+ (payment_method == CREDIT_CARD)
167
+ end
168
+
169
+ # * Return true if the invoice is cheque, else false.
170
+ # == Examples
171
+ # >>> invoice.cheque?
172
+ # => true
173
+ def cheque?
174
+ (payment_method == CHEQUE)
175
+ end
176
+
177
+ def can_be_draft?
178
+ active? or cancelled?
179
+ end
180
+
181
+ def can_be_active?
182
+ draft? or cancelled?
183
+ end
184
+
185
+ def can_be_cancelled?
186
+ draft? or active?
187
+ end
188
+
189
+ # TODO
190
+
191
+ def can_be_edited?
192
+ true
193
+ end
194
+
195
+ def can_be_deleted?
196
+ cancelled? && self.line_items.blank?
197
+ #if self.jobs.any?
198
+ # self.errors.add(:base, DELETE_MESSAGE)
199
+ # return false
200
+ #else
201
+ # return true
202
+ #end
203
+ #return true
204
+ end
205
+
206
+ def generate_real_invoice_number!
207
+ self.invoice_number = "INV-#{self.terminal.code}-#{self.id}"
208
+ self.save
209
+ end
210
+
211
+ def net_total_amount
212
+ self.total_amount - self.discount
213
+ end
214
+
215
+ def balance_to_give
216
+ self.money_taken - self.net_total_amount
217
+ end
218
+
219
+ def calculate_total_amount
220
+ self.total_amount = self.line_items.sum("rate * quantity") || 0.0
221
+ end
222
+
223
+ end
@@ -0,0 +1,206 @@
1
+ class LineItem < Vyapari::ApplicationRecord
2
+
3
+ # Constants
4
+ DRAFT = "draft"
5
+ SOLD = "sold"
6
+ DAMAGED = "damaged"
7
+ RETURNED = "returned"
8
+
9
+ STATUS_HASH = {"Draft" => DRAFT, "Sold" => SOLD, "Damaged" => DAMAGED, "Returned" => RETURNED}
10
+ STATUS_HASH_REVERSE = {DRAFT => "Draft", SOLD => "Sold", DAMAGED => "Damaged", RETURNED => "Returned"}
11
+
12
+ # Call backs
13
+ before_save :calculate_total_amount
14
+
15
+ # Validations
16
+ validates :product, :presence=> true
17
+ validates :quantity, :presence=> true
18
+ validates :rate, :presence=> true
19
+
20
+ validates :status, :presence=> true, :inclusion => {:in => STATUS_HASH_REVERSE.keys, :presence_of => :status, :message => "%{value} is not a valid status" }
21
+
22
+ # Associations
23
+ belongs_to :product, optional: true
24
+
25
+
26
+ # ------------------
27
+ # Class Methods
28
+ # ------------------
29
+
30
+ # Scopes
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
+ # >>> invoice.search(query)
36
+ # => ActiveRecord::Relation object
37
+ scope :search, lambda { |query| joins(:product).where("LOWER(products.name) LIKE LOWER('%#{query}%')")}
38
+ scope :status, lambda { |status| where("LOWER(status)='#{status}'") }
39
+
40
+ scope :draft, -> { where(status: DRAFT) }
41
+ scope :sold, -> { where(status: SOLD) }
42
+ scope :damaged, -> { where(status: DAMAGED) }
43
+ scope :returned, -> { where(status: RETURNED) }
44
+
45
+ scope :this_month, lambda { where("created_at >= ? AND created_at <= ?", Time.zone.now.beginning_of_month, Time.zone.now.end_of_month) }
46
+
47
+ # ------------------
48
+ # Instance Methods
49
+ # ------------------
50
+
51
+ def display_name
52
+ if product
53
+ self.product.display_name
54
+ else
55
+ "#{self.id} - No Product"
56
+ end
57
+ end
58
+
59
+ # * Return true if the invoice is sold, else false.
60
+ # == Examples
61
+ # >>> invoice.sold?
62
+ # => true
63
+ def sold?
64
+ (status == SOLD)
65
+ end
66
+
67
+ # change the status to :sold
68
+ # Return the status
69
+ # == Examples
70
+ # >>> invoice.publish!
71
+ # => "sold"
72
+ def sold!
73
+ self.update_attribute(:status, SOLD)
74
+ end
75
+
76
+ # * Return true if the invoice is active, else false.
77
+ # == Examples
78
+ # >>> invoice.active?
79
+ # => true
80
+ def active?
81
+ (status == ACTIVE)
82
+ end
83
+
84
+ # change the status to :active
85
+ # Return the status
86
+ # == Examples
87
+ # >>> invoice.unpublish!
88
+ # => "active"
89
+ def activate!
90
+ self.update_attributes(status: ACTIVE, featured: false)
91
+ end
92
+
93
+ # * Return true if the invoice is cancelled, else false.
94
+ # == Examples
95
+ # >>> invoice.cancelled?
96
+ # => true
97
+ def cancelled?
98
+ (status == CANCELLED)
99
+ end
100
+
101
+ # change the status to :cancelled
102
+ # Return the status
103
+ # == Examples
104
+ # >>> invoice.remove!
105
+ # => "cancelled"
106
+ def cancel!
107
+ self.update_attributes(status: CANCELLED, featured: false)
108
+ end
109
+
110
+ def can_be_sold?
111
+ active? or cancelled?
112
+ end
113
+
114
+ def can_be_active?
115
+ sold? or cancelled?
116
+ end
117
+
118
+ def can_be_cancelled?
119
+ sold? or active?
120
+ end
121
+
122
+ # change the status to :sold
123
+ # Return the status
124
+ # == Examples
125
+ # >>> stock_entry.sell!
126
+ # => "sold"
127
+ def sell!
128
+ self.update_attribute(:status, SOLD)
129
+ end
130
+
131
+ # change the status to :damaged
132
+ # Return the status
133
+ # == Examples
134
+ # >>> stock_entry.mark_as_damaged!
135
+ # => "damaged"
136
+ def mark_as_damaged!
137
+ self.update_attribute(:status, DAMAGED)
138
+ end
139
+
140
+ # change the status to :returned
141
+ # Return the status
142
+ # == Examples
143
+ # >>> stock_entry.reserve!
144
+ # => "returned"
145
+ def return!
146
+ self.update_attribute(:status, RETURN)
147
+ end
148
+
149
+ # change the status to :draft
150
+ # Return the status
151
+ # == Examples
152
+ # >>> stock_entry.draft!
153
+ # => "draft"
154
+ def draft!
155
+ self.update_attribute(:status, DRAFT)
156
+ end
157
+
158
+ # * Return true if the stock_entry is sold, else false.
159
+ # == Examples
160
+ # >>> stock_entry.sold?
161
+ # => true
162
+ def sold?
163
+ (status == SOLD)
164
+ end
165
+
166
+ # * Return true if the stock_entry is damaged, else false.
167
+ # == Examples
168
+ # >>> stock_entry.damaged?
169
+ # => true
170
+ def damaged?
171
+ (status == DAMAGED)
172
+ end
173
+
174
+ # * Return true if the stock_entry is returned, else false.
175
+ # == Examples
176
+ # >>> stock_entry.returned?
177
+ # => true
178
+ def returned?
179
+ (status == RETURNED)
180
+ end
181
+
182
+ def calculate_total_amount
183
+ if self.quantity * self.rate
184
+ self.total_amount = self.quantity * self.rate
185
+ else
186
+ self.total_amount = 0.00
187
+ end
188
+ end
189
+
190
+ # TODO
191
+ def can_be_edited?
192
+ true
193
+ end
194
+
195
+ def can_be_deleted?
196
+ true
197
+ #if self.jobs.any?
198
+ # self.errors.add(:base, DELETE_MESSAGE)
199
+ # return false
200
+ #else
201
+ # return true
202
+ #end
203
+ #return true
204
+ end
205
+
206
+ end
@@ -4,6 +4,7 @@ class Product < Vyapari::ApplicationRecord
4
4
  PUBLISHED = "published"
5
5
  UNPUBLISHED = "unpublished"
6
6
  REMOVED = "removed"
7
+
7
8
  STATUS_HASH = {"Published" => PUBLISHED, "Unpublished" => UNPUBLISHED, "Removed" => REMOVED}
8
9
  STATUS_HASH_REVERSE = {PUBLISHED => "Published", UNPUBLISHED => "Unpublished", REMOVED => "Removed"}
9
10
 
@@ -11,18 +12,18 @@ class Product < Vyapari::ApplicationRecord
11
12
  FEATURED_HASH_REVERSE = {true => "Featured", false => "Non Featured"}
12
13
 
13
14
  # Callbacks
14
- before_validation :update_permalink
15
15
  before_validation :update_top_category
16
16
 
17
17
  # Validations
18
18
  validates :name, presence: true
19
+ validates :ean_sku, presence: true
20
+
19
21
  #validates :description, presence: true
20
- validates :permalink, presence: true, uniqueness: true
21
22
  validates :status, :presence=> true, :inclusion => {:in => STATUS_HASH_REVERSE.keys, :presence_of => :status, :message => "%{value} is not a valid status" }
22
23
 
23
24
  # Associations
24
25
  has_one :product_image, :as => :imageable, :dependent => :destroy, :class_name => "Image::ProductImage"
25
- has_one :brochure, :as => :documentable, :dependent => :destroy, :class_name => "Document::Brochure"
26
+ #has_one :brochure, :as => :documentable, :dependent => :destroy, :class_name => "Document::Brochure"
26
27
 
27
28
  belongs_to :brand
28
29
  belongs_to :category
@@ -35,7 +36,6 @@ class Product < Vyapari::ApplicationRecord
35
36
  # => ActiveRecord::Relation object
36
37
  scope :search, lambda {|query| joins("INNER JOIN categories on categories.id = products.category_id").
37
38
  where("LOWER(products.name) LIKE LOWER('%#{query}%') OR\
38
- LOWER(products.permalink) LIKE LOWER('%#{query}%') OR\
39
39
  LOWER(products.one_liner) LIKE LOWER('%#{query}%') OR\
40
40
  LOWER(products.description) LIKE LOWER('%#{query}%') OR\
41
41
  LOWER(categories.name) LIKE LOWER('%#{query}%') OR\
@@ -50,10 +50,57 @@ class Product < Vyapari::ApplicationRecord
50
50
  scope :unpublished, -> { where(status: UNPUBLISHED) }
51
51
  scope :removed, -> { where(status: REMOVED) }
52
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[:name].blank?
58
+
59
+ product = Product.find_by_name(row[:name]) || Product.new
60
+
61
+ product.name = row[:name]
62
+ product.one_liner = row[:one_liner]
63
+ product.description = row[:description]
64
+ product.ean_sku = row[:ean_sku]
65
+ product.reference_number = row[:reference_number]
66
+
67
+ product.brand = Brand.find_by_name(row[:brand])
68
+ product.category = Category.find_by_name(row[:category])
69
+ product.top_category = product.category.top_category if product.category
70
+
71
+ product.featured = row[:featured]
72
+ product.status = row[:status]
73
+ product.priority = row[:priority]
74
+
75
+ # Initializing error hash for displaying all errors altogether
76
+ error_object = Kuppayam::Importer::ErrorHash.new
77
+
78
+ if product.valid?
79
+ product.save!
80
+ else
81
+ summary = "Error while saving product: #{product.name}"
82
+ details = "Error! #{product.errors.full_messages.to_sentence}"
83
+ error_object.errors << { summary: summary, details: details }
84
+ end
85
+ return error_object
86
+ end
87
+
53
88
  # ------------------
54
89
  # Instance variables
55
90
  # ------------------
56
91
 
92
+ def display_name
93
+ "#{self.ean_sku} : #{self.name}"
94
+ end
95
+
96
+ def slug
97
+ self.name.parameterize
98
+ end
99
+
100
+ def to_param
101
+ "#{id}-#{slug}"
102
+ end
103
+
57
104
  # * Return true if the brand is published, else false.
58
105
  # == Examples
59
106
  # >>> brand.published?
@@ -105,7 +152,22 @@ class Product < Vyapari::ApplicationRecord
105
152
  self.update_attributes(status: REMOVED, featured: false)
106
153
  end
107
154
 
108
- # TODO
155
+ def can_be_published?
156
+ unpublished? or removed?
157
+ end
158
+
159
+ def can_be_unpublished?
160
+ published? or removed?
161
+ end
162
+
163
+ def can_be_removed?
164
+ published? or unpublished? or removed?
165
+ end
166
+
167
+ def can_be_edited?
168
+ true
169
+ end
170
+
109
171
  def can_be_deleted?
110
172
  #if self.jobs.any?
111
173
  # self.errors.add(:base, DELETE_MESSAGE)
@@ -116,10 +178,6 @@ class Product < Vyapari::ApplicationRecord
116
178
  return true
117
179
  end
118
180
 
119
- def default_image_url(size="medium")
120
- "/assets/defaults/product-#{size}.png"
121
- end
122
-
123
181
  protected
124
182
 
125
183
  def update_top_category
@@ -132,8 +190,4 @@ class Product < Vyapari::ApplicationRecord
132
190
  end
133
191
  end
134
192
 
135
- def update_permalink
136
- self.permalink = "#{id}-#{name.parameterize}" if self.permalink.blank?
137
- end
138
-
139
193
  end
data/app/models/region.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  class Region < Vyapari::ApplicationRecord
2
2
 
3
- DELETE_MESSAGE = "Cannot delete this Region. You should first delete all the dependant data like Company Cities, Jobs, Budgets etc tagged with this Region"
4
-
5
3
  # Validations
6
4
  validates :name, presence: true, length: {minimum: 2, maximum: 250}, allow_blank: false
7
5
  validates :code, presence: true, uniqueness: true, length: {minimum: 2, maximum: 32}, allow_blank: false
@@ -9,7 +7,7 @@ class Region < Vyapari::ApplicationRecord
9
7
 
10
8
  # Associations
11
9
  belongs_to :country
12
- # has_many :stores
10
+ has_many :stores
13
11
 
14
12
  # ------------------
15
13
  # Class Methods
@@ -22,6 +20,31 @@ class Region < Vyapari::ApplicationRecord
22
20
  # => ActiveRecord::Relation object
23
21
  scope :search, lambda {|query| joins(:country).where("LOWER(cities.name) LIKE LOWER('%#{query}%') OR LOWER(countries.name) LIKE LOWER('%#{query}%')")}
24
22
 
23
+ def self.save_row_data(row)
24
+
25
+ row.headers.each{ |cell| row[cell] = row[cell].to_s.strip }
26
+
27
+ return if row[:name].blank?
28
+
29
+ region = Region.find_by_code(row[:code]) || Region.new
30
+ region.name = row[:name]
31
+ region.code = row[:code]
32
+ region.country = Country.find_by_code(row[:country]) || Country.find_by_name(row[:country])
33
+
34
+ # Initializing error hash for displaying all errors altogether
35
+ error_object = Kuppayam::Importer::ErrorHash.new
36
+
37
+ if region.valid?
38
+ region.save!
39
+ else
40
+ summary = "Error while saving region: #{region.name}"
41
+ details = "Error! #{region.errors.full_messages.to_sentence}"
42
+ error_object.errors << { summary: summary, details: details }
43
+ end
44
+
45
+ return error_object
46
+ end
47
+
25
48
  # ------------------
26
49
  # Instance Methods
27
50
  # ------------------