stockor 0.1.5

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 (259) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/Gemfile +11 -0
  4. data/Gemfile.lock +220 -0
  5. data/Guardfile +13 -0
  6. data/README.md +7 -0
  7. data/Rakefile +7 -0
  8. data/client/skr/Extension.coffee +12 -0
  9. data/client/skr/components/.gitkeep +0 -0
  10. data/client/skr/components/address/Address.coffee +21 -0
  11. data/client/skr/components/address/address.html +20 -0
  12. data/client/skr/index.js +21 -0
  13. data/client/skr/models/Address.coffee +17 -0
  14. data/client/skr/models/Base.coffee +8 -0
  15. data/client/skr/models/Customer.coffee +26 -0
  16. data/client/skr/models/GlAccount.coffee +10 -0
  17. data/client/skr/models/GlManualEntry.coffee +11 -0
  18. data/client/skr/models/GlPeriod.coffee +10 -0
  19. data/client/skr/models/GlPosting.coffee +15 -0
  20. data/client/skr/models/GlTransaction.coffee +16 -0
  21. data/client/skr/models/IaLine.coffee +19 -0
  22. data/client/skr/models/IaReason.coffee +12 -0
  23. data/client/skr/models/InvLine.coffee +27 -0
  24. data/client/skr/models/InventoryAdjustment.coffee +17 -0
  25. data/client/skr/models/Invoice.coffee +31 -0
  26. data/client/skr/models/Location.coffee +15 -0
  27. data/client/skr/models/PaymentTerm.coffee +11 -0
  28. data/client/skr/models/PickTicket.coffee +19 -0
  29. data/client/skr/models/PoLine.coffee +27 -0
  30. data/client/skr/models/PoReceipt.coffee +20 -0
  31. data/client/skr/models/PorLine.coffee +26 -0
  32. data/client/skr/models/PtLine.coffee +27 -0
  33. data/client/skr/models/PurchaseOrder.coffee +23 -0
  34. data/client/skr/models/SalesOrder.coffee +32 -0
  35. data/client/skr/models/Sku.coffee +21 -0
  36. data/client/skr/models/SkuLoc.coffee +21 -0
  37. data/client/skr/models/SkuTran.coffee +23 -0
  38. data/client/skr/models/SkuVendor.coffee +19 -0
  39. data/client/skr/models/SoLine.coffee +27 -0
  40. data/client/skr/models/Uom.coffee +17 -0
  41. data/client/skr/models/Vendor.coffee +28 -0
  42. data/client/skr/models/VoLine.coffee +23 -0
  43. data/client/skr/models/Voucher.coffee +22 -0
  44. data/client/skr/models/mixins/CodeField.coffee +5 -0
  45. data/client/skr/screens/.gitkeep +0 -0
  46. data/client/skr/screens/Base.coffee +3 -0
  47. data/client/skr/screens/base/index.js +5 -0
  48. data/client/skr/screens/base/index.scss +9 -0
  49. data/client/skr/screens/base/layout.html +3 -0
  50. data/client/skr/screens/customer-maint/CustomerMaint.coffee +49 -0
  51. data/client/skr/screens/customer-maint/index.js +5 -0
  52. data/client/skr/screens/customer-maint/index.scss +9 -0
  53. data/client/skr/screens/customer-maint/layout.html +32 -0
  54. data/client/skr/styles.scss +1 -0
  55. data/client/skr/views/.gitkeep +0 -0
  56. data/client/skr/views/Base.coffee +5 -0
  57. data/config/database.yml +9 -0
  58. data/config/lanes.rb +7 -0
  59. data/config/routes.rb +39 -0
  60. data/config/screens.rb +17 -0
  61. data/config.ru +5 -0
  62. data/db/.gitkeep +0 -0
  63. data/db/migrate/20120110142845_create_skr_sequential_ids.rb +35 -0
  64. data/db/migrate/20140202185309_create_skr_gl_accounts.rb +15 -0
  65. data/db/migrate/20140202193316_create_skr_gl_periods.rb +16 -0
  66. data/db/migrate/20140202193318_create_skr_gl_transactions.rb +14 -0
  67. data/db/migrate/20140202193319_create_skr_gl_postings.rb +16 -0
  68. data/db/migrate/20140202193700_create_skr_gl_manual_entries.rb +13 -0
  69. data/db/migrate/20140213040608_create_skr_payment_terms.rb +16 -0
  70. data/db/migrate/20140220031700_create_skr_addresses.rb +19 -0
  71. data/db/migrate/20140220031800_create_skr_locations.rb +19 -0
  72. data/db/migrate/20140220190836_create_skr_vendors.rb +22 -0
  73. data/db/migrate/20140220203029_create_skr_customers.rb +22 -0
  74. data/db/migrate/20140224034759_create_skr_skus.rb +22 -0
  75. data/db/migrate/20140225032853_create_skr_sku_locs.rb +21 -0
  76. data/db/migrate/20140320030501_create_skr_uoms.rb +19 -0
  77. data/db/migrate/20140321031604_create_skr_sku_vendors.rb +18 -0
  78. data/db/migrate/20140322012143_create_skr_ia_reasons.rb +14 -0
  79. data/db/migrate/20140322014401_create_skr_inventory_adjustments.rb +16 -0
  80. data/db/migrate/20140322023453_create_skr_ia_lines.rb +18 -0
  81. data/db/migrate/20140322035024_create_skr_sku_trans.rb +21 -0
  82. data/db/migrate/20140322223912_create_skr_sales_orders.rb +27 -0
  83. data/db/migrate/20140322223920_create_skr_so_lines.rb +25 -0
  84. data/db/migrate/20140323001446_create_so_details_view.rb +81 -0
  85. data/db/migrate/20140327202102_create_skr_purchase_orders.rb +20 -0
  86. data/db/migrate/20140327202107_create_skr_po_lines.rb +25 -0
  87. data/db/migrate/20140327202207_create_skr_pick_tickets.rb +16 -0
  88. data/db/migrate/20140327202209_create_skr_pt_lines.rb +23 -0
  89. data/db/migrate/20140327224000_create_skr_invoices.rb +25 -0
  90. data/db/migrate/20140327224002_create_skr_inv_lines.rb +23 -0
  91. data/db/migrate/20140330232808_create_skr_sku_loc_details_view.rb +31 -0
  92. data/db/migrate/20140330232810_create_skr_sku_qty_details_view.rb +48 -0
  93. data/db/migrate/20140400164729_create_skr_vouchers.rb +22 -0
  94. data/db/migrate/20140400164733_create_skr_vo_lines.rb +21 -0
  95. data/db/migrate/20140401164729_create_skr_po_receipt.rb +16 -0
  96. data/db/migrate/20140401164740_create_skr_por_line.rb +21 -0
  97. data/db/migrate/20140422024010_create_skr_inv_details_view.rb +42 -0
  98. data/db/schema.sql +2662 -0
  99. data/db/seed/chart_of_accounts.yml +168 -0
  100. data/db/seed/payment_terms.yml +60 -0
  101. data/db/seed.rb +29 -0
  102. data/lib/skr/access_roles.rb +28 -0
  103. data/lib/skr/concerns/acts_as_uom.rb +47 -0
  104. data/lib/skr/concerns/code_identifier.rb +43 -0
  105. data/lib/skr/concerns/gl_tran_extensions.rb +18 -0
  106. data/lib/skr/concerns/has_gl_transaction.rb +67 -0
  107. data/lib/skr/concerns/has_sku_loc_lines.rb +47 -0
  108. data/lib/skr/concerns/immutable_model.rb +32 -0
  109. data/lib/skr/concerns/inv_extensions.rb +24 -0
  110. data/lib/skr/concerns/is_order_like.rb +47 -0
  111. data/lib/skr/concerns/is_sku_loc_line.rb +65 -0
  112. data/lib/skr/concerns/locked_fields.rb +84 -0
  113. data/lib/skr/concerns/pt_extensions.rb +22 -0
  114. data/lib/skr/concerns/random_hash_code.rb +40 -0
  115. data/lib/skr/concerns/so_extensions.rb +30 -0
  116. data/lib/skr/concerns/state_machine.rb +61 -0
  117. data/lib/skr/concerns/visible_id_identifier.rb +53 -0
  118. data/lib/skr/configuration.rb +68 -0
  119. data/lib/skr/db/migration_helpers.rb +178 -0
  120. data/lib/skr/extension.rb +23 -0
  121. data/lib/skr/model.rb +19 -0
  122. data/lib/skr/models/address.rb +97 -0
  123. data/lib/skr/models/business_entity.rb +29 -0
  124. data/lib/skr/models/customer.rb +35 -0
  125. data/lib/skr/models/gl_account.rb +56 -0
  126. data/lib/skr/models/gl_manual_entry.rb +31 -0
  127. data/lib/skr/models/gl_period.rb +13 -0
  128. data/lib/skr/models/gl_posting.rb +54 -0
  129. data/lib/skr/models/gl_transaction.rb +175 -0
  130. data/lib/skr/models/ia_line.rb +129 -0
  131. data/lib/skr/models/ia_reason.rb +16 -0
  132. data/lib/skr/models/inv_line.rb +90 -0
  133. data/lib/skr/models/inventory_adjustment.rb +60 -0
  134. data/lib/skr/models/invoice.rb +159 -0
  135. data/lib/skr/models/location.rb +31 -0
  136. data/lib/skr/models/payment_term.rb +30 -0
  137. data/lib/skr/models/pick_ticket.rb +71 -0
  138. data/lib/skr/models/po_line.rb +69 -0
  139. data/lib/skr/models/po_receipt.rb +51 -0
  140. data/lib/skr/models/por_line.rb +80 -0
  141. data/lib/skr/models/pt_line.rb +74 -0
  142. data/lib/skr/models/purchase_order.rb +112 -0
  143. data/lib/skr/models/sales_order.rb +159 -0
  144. data/lib/skr/models/sequential_id.rb +23 -0
  145. data/lib/skr/models/sku.rb +99 -0
  146. data/lib/skr/models/sku_loc.rb +94 -0
  147. data/lib/skr/models/sku_tran.rb +111 -0
  148. data/lib/skr/models/sku_vendor.rb +26 -0
  149. data/lib/skr/models/so_line.rb +159 -0
  150. data/lib/skr/models/uom.rb +63 -0
  151. data/lib/skr/models/user_proxy.rb +60 -0
  152. data/lib/skr/models/vendor.rb +33 -0
  153. data/lib/skr/models/vo_line.rb +35 -0
  154. data/lib/skr/models/voucher.rb +119 -0
  155. data/lib/skr/standard_pricing_provider.rb +14 -0
  156. data/lib/skr/version.rb +3 -0
  157. data/lib/skr.rb +18 -0
  158. data/lib/stockor.rb +4 -0
  159. data/lib/tasks/debug-activity.rake +58 -0
  160. data/log/test.log +0 -0
  161. data/spec/fixtures/skr/address.yml +2 -0
  162. data/spec/fixtures/skr/customer.yml +2 -0
  163. data/spec/fixtures/skr/gl_account.yml +2 -0
  164. data/spec/fixtures/skr/gl_manual_entry.yml +2 -0
  165. data/spec/fixtures/skr/gl_period.yml +2 -0
  166. data/spec/fixtures/skr/gl_posting.yml +2 -0
  167. data/spec/fixtures/skr/gl_transaction.yml +2 -0
  168. data/spec/fixtures/skr/ia_line.yml +2 -0
  169. data/spec/fixtures/skr/ia_reason.yml +2 -0
  170. data/spec/fixtures/skr/inv_line.yml +2 -0
  171. data/spec/fixtures/skr/inventory_adjustment.yml +2 -0
  172. data/spec/fixtures/skr/invoice.yml +2 -0
  173. data/spec/fixtures/skr/location.yml +2 -0
  174. data/spec/fixtures/skr/payment_term.yml +2 -0
  175. data/spec/fixtures/skr/pick_ticket.yml +2 -0
  176. data/spec/fixtures/skr/po_line.yml +2 -0
  177. data/spec/fixtures/skr/po_receipt.yml +2 -0
  178. data/spec/fixtures/skr/por_line.yml +2 -0
  179. data/spec/fixtures/skr/pt_line.yml +2 -0
  180. data/spec/fixtures/skr/purchase_order.yml +2 -0
  181. data/spec/fixtures/skr/sales_order.yml +2 -0
  182. data/spec/fixtures/skr/sku.yml +2 -0
  183. data/spec/fixtures/skr/sku_loc.yml +2 -0
  184. data/spec/fixtures/skr/sku_tran.yml +2 -0
  185. data/spec/fixtures/skr/sku_vendor.yml +2 -0
  186. data/spec/fixtures/skr/so_line.yml +2 -0
  187. data/spec/fixtures/skr/uom.yml +2 -0
  188. data/spec/fixtures/skr/vendor.yml +2 -0
  189. data/spec/fixtures/skr/vo_line.yml +2 -0
  190. data/spec/fixtures/skr/voucher.yml +2 -0
  191. data/spec/skr/address.rb +10 -0
  192. data/spec/skr/concerns/code_identifier_spec.rb +45 -0
  193. data/spec/skr/customer.rb +10 -0
  194. data/spec/skr/gl_account.rb +10 -0
  195. data/spec/skr/gl_manual_entry.rb +10 -0
  196. data/spec/skr/gl_period.rb +10 -0
  197. data/spec/skr/gl_posting.rb +10 -0
  198. data/spec/skr/gl_transaction.rb +10 -0
  199. data/spec/skr/ia_line.rb +10 -0
  200. data/spec/skr/ia_reason.rb +10 -0
  201. data/spec/skr/inv_line.rb +10 -0
  202. data/spec/skr/inventory_adjustment.rb +10 -0
  203. data/spec/skr/invoice.rb +10 -0
  204. data/spec/skr/location.rb +10 -0
  205. data/spec/skr/models/AddressSpec.coffee +5 -0
  206. data/spec/skr/models/CustomerSpec.coffee +5 -0
  207. data/spec/skr/models/GlAccountSpec.coffee +5 -0
  208. data/spec/skr/models/GlManualEntrySpec.coffee +5 -0
  209. data/spec/skr/models/GlPeriodSpec.coffee +5 -0
  210. data/spec/skr/models/GlPostingSpec.coffee +5 -0
  211. data/spec/skr/models/GlTransactionSpec.coffee +5 -0
  212. data/spec/skr/models/IaLineSpec.coffee +5 -0
  213. data/spec/skr/models/IaReasonSpec.coffee +5 -0
  214. data/spec/skr/models/InvLineSpec.coffee +5 -0
  215. data/spec/skr/models/InventoryAdjustmentSpec.coffee +5 -0
  216. data/spec/skr/models/InvoiceSpec.coffee +5 -0
  217. data/spec/skr/models/LocationSpec.coffee +5 -0
  218. data/spec/skr/models/PaymentTermSpec.coffee +5 -0
  219. data/spec/skr/models/PickTicketSpec.coffee +5 -0
  220. data/spec/skr/models/PoLineSpec.coffee +5 -0
  221. data/spec/skr/models/PoReceiptSpec.coffee +5 -0
  222. data/spec/skr/models/PorLineSpec.coffee +5 -0
  223. data/spec/skr/models/PtLineSpec.coffee +5 -0
  224. data/spec/skr/models/PurchaseOrderSpec.coffee +5 -0
  225. data/spec/skr/models/SalesOrderSpec.coffee +5 -0
  226. data/spec/skr/models/SkuLocSpec.coffee +5 -0
  227. data/spec/skr/models/SkuSpec.coffee +5 -0
  228. data/spec/skr/models/SkuTranSpec.coffee +5 -0
  229. data/spec/skr/models/SkuVendorSpec.coffee +5 -0
  230. data/spec/skr/models/SoLineSpec.coffee +5 -0
  231. data/spec/skr/models/UomSpec.coffee +5 -0
  232. data/spec/skr/models/VendorSpec.coffee +5 -0
  233. data/spec/skr/models/VoLineSpec.coffee +5 -0
  234. data/spec/skr/models/VoucherSpec.coffee +5 -0
  235. data/spec/skr/payment_term.rb +10 -0
  236. data/spec/skr/pick_ticket.rb +10 -0
  237. data/spec/skr/po_line.rb +10 -0
  238. data/spec/skr/po_receipt.rb +10 -0
  239. data/spec/skr/por_line.rb +10 -0
  240. data/spec/skr/pt_line.rb +10 -0
  241. data/spec/skr/purchase_order.rb +10 -0
  242. data/spec/skr/sales_order.rb +10 -0
  243. data/spec/skr/screens/Base.coffee +7 -0
  244. data/spec/skr/screens/CustomerMaint.coffee +7 -0
  245. data/spec/skr/screens/vendor-maint/VendorMaintSpec.coffee +5 -0
  246. data/spec/skr/sku.rb +10 -0
  247. data/spec/skr/sku_loc.rb +10 -0
  248. data/spec/skr/sku_tran.rb +10 -0
  249. data/spec/skr/sku_vendor.rb +10 -0
  250. data/spec/skr/so_line.rb +10 -0
  251. data/spec/skr/spec_helper.rb +26 -0
  252. data/spec/skr/uom.rb +10 -0
  253. data/spec/skr/vendor.rb +10 -0
  254. data/spec/skr/views/AddressSpec.coffee +5 -0
  255. data/spec/skr/vo_line.rb +10 -0
  256. data/spec/skr/voucher.rb +10 -0
  257. data/stockor.gemspec +38 -0
  258. data/tmp/.gitkeep +0 -0
  259. metadata +414 -0
@@ -0,0 +1,84 @@
1
+ module Skr
2
+ module Concerns
3
+
4
+ # @see ClassMethods
5
+ module LockedFields
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # Mark fields as locked, meaning they cannot be updated by using the
10
+ # regular attribute update methods. Instead it must be called in an unlock block
11
+ # Relies on attr_readonly internally
12
+ #
13
+ # Is used to designate sensitive fields that we want to make sure someone's thought about before updating
14
+ # Also solves the age old single equals vs double equals bug/typo.
15
+ #
16
+ # class BankAccount < Skr::Model
17
+ #
18
+ # end
19
+ #
20
+ # bank=BankAccount.find(1)
21
+ # b.mark_as_super if bank.account_balance = 42 # a bit contrived, but you get the idea
22
+ # b.save # oops, what's our balance now?
23
+ #
24
+ # Now let's try it again with locked_fields
25
+ #
26
+ # class BankAccount < Skr::Model
27
+ # attr_readonly :account_balance
28
+ # end
29
+ #
30
+ # bank=BankAccount.find(1)
31
+ # b.mark_as_super if bank.account_balance = 42
32
+ # b.save # Still not ideal since we marked the bank as super, but at least our balance is ok
33
+ #
34
+ # To update the balance we'd need to:
35
+ #
36
+ # b.unlock_fields( :account_balance ) do
37
+ # b.account_balance += 33
38
+ # end
39
+ # b.save
40
+ #
41
+ # This is still a bit contrived since we'd actually have
42
+ # an audit logger that would be involved and it'd be inside a transaction.
43
+
44
+ def locked_fields( *flds )
45
+ include InstanceMethods
46
+ attr_readonly( *flds )
47
+ end
48
+
49
+ def has_locks( *locks )
50
+ locks.each do | lock |
51
+ define_method( "unlock_#{lock}" ) do | &block |
52
+ instance_variable_set "@_lock_#{lock}_unlocked", true
53
+ block.call
54
+ remove_instance_variable "@_lock_#{lock}_unlocked"
55
+ end
56
+ define_method( "is_#{lock}_unlocked?") do
57
+ instance_variable_defined? "@_lock_#{lock}_unlocked"
58
+ end
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ module InstanceMethods
65
+ # Unlock the field for updates inside the block
66
+ # yields, then restores it.
67
+ # Is class wide, meaning it Will temporarily open all instances of the class up for access in a threaded environment
68
+ def unlock_fields( *flds, &block )
69
+ attr_syms = flds.map(&:to_s)
70
+
71
+ self.class.attr_readonly.subtract( attr_syms )
72
+
73
+ yield
74
+
75
+ attr_syms.each do | fld |
76
+ self.class.attr_readonly.add( fld )
77
+ end
78
+
79
+ end
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,22 @@
1
+ module Skr
2
+ module Concerns
3
+
4
+ module PT
5
+
6
+ module Lines
7
+
8
+ def set_ship_qty
9
+ each{|l| l.qty_to_ship = l.qty }
10
+ end
11
+
12
+ def ea_picking_qty
13
+ if proxy_association.loaded?
14
+ inject(0){ | sum, ptl | sum+(ptl.qty*ptl.uom_size) unless ptl.is_complete? }
15
+ else
16
+ where( is_complete: false ).sum('qty*uom_size')
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,40 @@
1
+ module Skr
2
+ module Concerns
3
+
4
+ # @see ClassMethods
5
+ module RandomHashCode
6
+
7
+ extend ActiveSupport::Concern
8
+
9
+ # ### Random Hash Code Concern
10
+ # This adds the {#has_random_hash_code} class method
11
+ module ClassMethods
12
+
13
+ # A random string that identifies an entity, such as a Customer, or Vendor
14
+ # The code is generated by {Skr::Strings.random} for new records
15
+ # It's useful for generating *magic* links for access to an entity that cannot be guessed.
16
+ # @param field_name [Symbol] which field should the hash_code be stored in
17
+ # @param length [Integer] how long the hash_code should be
18
+
19
+ def has_random_hash_code( field_name: :hash_code, length: 12 )
20
+
21
+ validates field_name, :presence=>{
22
+ :message=>"hash code is not set (should be automatically chosen)"
23
+ }
24
+
25
+ scope :with_hash_code, lambda{ | code |
26
+ where({ :hash_code=>code })
27
+ }
28
+
29
+ before_validation(:on=>:create) do
30
+ self[ field_name ] = Lanes::Strings.random( length ) if self[ field_name ].blank?
31
+ end
32
+
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,30 @@
1
+ module Skr
2
+ module Concerns
3
+
4
+ module SO
5
+
6
+ module Lines
7
+
8
+ def set_ship_qty
9
+ each{|l| l.qty_to_ship = l.qty }
10
+ end
11
+
12
+ def eq_qty
13
+ if proxy_association.loaded?
14
+ inject(0){ | sum, sol | sum + (sol.eq_qty*uom_size) }
15
+ else
16
+ sum('qty*uom_size')
17
+ end
18
+ end
19
+
20
+ def eq_qty_allocated
21
+ if proxy_association.loaded?
22
+ inject(0){ | sum, sol | sum + (sol.qty_allocated * uom_size) }
23
+ else
24
+ sum('qty_allocated*uom_size')
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,61 @@
1
+ require 'aasm' # Acts As State Machine
2
+
3
+ module Skr
4
+ module Concerns
5
+
6
+
7
+ # Models that use the {https://github.com/aasm/aasm}
8
+ # gem to track object state
9
+ module StateMachine
10
+
11
+ extend ActiveSupport::Concern
12
+
13
+ module ClassMethods
14
+
15
+ # Mark class as a StateMachine {https://github.com/aasm/aasm}
16
+ #
17
+ # Specifically it:
18
+ #
19
+ # * Adds the methods in {InstanceMethods} to the class
20
+ # * Blacklists the "state" field so it cannot be set via the API
21
+ # * Allows access to the "state_event" pseudo field from the API
22
+ # * Sets up the aasm library with the contents of &block
23
+ def state_machine( options={}, &block )
24
+ include InstanceMethods
25
+ include AASM
26
+ aasm( options.merge( column: 'state' ), &block )
27
+
28
+ whitelist_attributes :state_event
29
+
30
+ export_methods :valid_state_events, :optional=>false
31
+ blacklist_attributes :state
32
+
33
+ before_save :fire_state_machine_event_on_save
34
+ end
35
+
36
+ end
37
+
38
+ module InstanceMethods
39
+
40
+ def fire_state_machine_event_on_save
41
+ return unless state_event.present?
42
+ event_name = state_event.to_sym
43
+ if valid_state_events.include?( event_name )
44
+ self.send( :aasm_fire_event, event_name, {:persist=>false} )
45
+ else
46
+ errors.add(:state_event, "is not valid")
47
+ false
48
+ end
49
+ end
50
+
51
+ # @return [Array of symbols] the available state_transistions
52
+ def valid_state_events
53
+ aasm.events
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,53 @@
1
+ module Skr
2
+ module Concerns
3
+
4
+ # @see ClassMethods
5
+ module VisibleIdIdentifier
6
+
7
+ extend ActiveSupport::Concern
8
+
9
+ module InstanceMethods
10
+
11
+ # setup the visible id to the next available #{Skr::SequentialId}
12
+ # @return [Integer] the assigned ID
13
+ def assign_visible_id!
14
+ self.visible_id = Skr::SequentialId.next_for( self.class )
15
+ end
16
+ end
17
+
18
+
19
+ # ### Visible ID Identifier Concern
20
+ # This adds the {#has_visible_id} class methods
21
+ module ClassMethods
22
+
23
+ # An auto-incrementing number that's user-visible.
24
+ # The visible_id is stored as an integer, but a string index is generated for
25
+ # querying by the sql like operator. The **with_visible_id** scope is available for this purpose
26
+ #
27
+ # The next number an also be adjusted by the end-user by setting {Skr::SequentialId}
28
+ # so they can set the numbers to start at
29
+ # a specific point, which is useful for getting Invoice and other
30
+ # numbers to match up to a legacy system
31
+ def has_visible_id
32
+ include InstanceMethods
33
+ validates :visible_id, :presence=>{
34
+ :message=>"ID was not set (should be automatically chosen)"
35
+ }
36
+ alias_attribute :record_identifier, :visible_id
37
+ before_validation :assign_visible_id!, :on=>:create
38
+
39
+ export_scope :with_visible_id, lambda{ | visid |
40
+ if visid.to_s =~/%/
41
+ where( 'cast(visible_id as varchar) like ?', visid.to_s )
42
+ else
43
+ where( 'cast(visible_id as varchar) = ?', visid.to_s )
44
+ end
45
+ }
46
+
47
+ end
48
+
49
+ end
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,68 @@
1
+ require 'lanes/configuration'
2
+ require_relative 'standard_pricing_provider'
3
+
4
+ module Skr
5
+
6
+ class Configuration < Lanes::Configuration
7
+
8
+ # Database tables will have this prefix applied to them
9
+ config_option :table_prefix, 'skr_'
10
+
11
+ # The GL branch code to use for default newly created locations
12
+ config_option :default_branch_code, '01'
13
+
14
+ # The string value of the UserModel. Will be set on model's updated_by and created_by
15
+ config_option :user_model, 'UserProxy'
16
+
17
+ # Transactions that do not specify a location will use the one that's identified by this code
18
+ config_option :default_location_code, 'DEFAULT'
19
+
20
+ # Do freshly created SKUs default to being backorderable?
21
+ config_option :skus_backorder_default, true
22
+
23
+ # The code for a Sku that represents tax
24
+ config_option :tax_sku_code, 'TAX'
25
+
26
+ # Code for a Sku that represents shipping charges
27
+ config_option :ship_sku_code, 'SHIP'
28
+
29
+ # Code for a PaymentTerm that will be used as the default for new Customers
30
+ config_option :customer_terms_code, 'CASH'
31
+
32
+ # Code for a PaymentTerm that will be used as the default for new Vendors
33
+ config_option :vendor_terms_code, 'CASH'
34
+
35
+ config_option :pricing_provider, Skr::StandardPricingProvider
36
+
37
+ config_option :default_gl_accounts, {
38
+ # The Accounts Receivable (AR) GL account number to use for freshly created Customers
39
+ ar: '1200',
40
+ # The Accounts Payable (AP) GL account number to use for freshly created Vendors
41
+ ap: '2200',
42
+ # The Freight GL account number to use for freshly created Vendors
43
+ freight: '6420',
44
+ # The Asset GL account number to use for freshly created SKUs
45
+ asset: '1100',
46
+ # Clearing account for inventory that's been
47
+ inventory_receipts_clearing: '2600',
48
+ # Holding account for funds that are awaiting deposit
49
+ deposit_holding: '1010'
50
+ }
51
+ end
52
+
53
+
54
+
55
+ class << self
56
+ @@config = Configuration.new
57
+ def config
58
+ @@config
59
+ end
60
+
61
+ def configure
62
+ yield(@@config)
63
+ end
64
+ end
65
+
66
+
67
+
68
+ end
@@ -0,0 +1,178 @@
1
+ require 'lanes/configuration'
2
+
3
+ module Skr
4
+
5
+ module DB
6
+
7
+ module TableFields
8
+
9
+ def skr_code_identifier
10
+ column( :code, :string, :null=>false )
11
+ skr_extra_indexes['code'] = {}
12
+ end
13
+
14
+ def skr_visible_id
15
+ column( :visible_id, :integer, :null=>false )
16
+ skr_extra_indexes['visible_id'] = {
17
+ function: 'CAST(visible_id AS VARCHAR)'
18
+ }
19
+ end
20
+
21
+ # track modifications
22
+ def skr_track_modifications( create_only: false )
23
+ column( :created_at, :datetime, :null=>false )
24
+ column( :created_by_id, :integer, :null=>false )
25
+ unless create_only
26
+ column( :updated_at, :datetime, :null=>false )
27
+ column( :updated_by_id, :integer, :null=>false )
28
+ end
29
+ end
30
+
31
+ def skr_currency( names, options )
32
+ options[ :precision ] ||= 15
33
+ options[ :scale ] ||= 2
34
+ column( names, :decimal, options )
35
+ end
36
+
37
+ # An skr_reference combines a belongs_to / has_one column
38
+ # with a postgresql foreign key reference.
39
+ def skr_reference( to_table, *args )
40
+ options = args.extract_options!
41
+
42
+ options[:column] ||= to_table.to_s + '_id'
43
+
44
+ column( options[:column], :integer, :null=>options[:null] || false )
45
+ to_table = options[:to_table] if options.has_key? :to_table
46
+
47
+ if options[:single]
48
+ to_table = to_table.to_s.pluralize
49
+ end
50
+ skr_foreign_keys[ to_table.to_sym ] = options
51
+ end
52
+
53
+ def skr_foreign_keys
54
+ @skr_foreign_keys ||= {}
55
+ end
56
+
57
+ def skr_extra_indexes
58
+ @skr_extra_indexs ||= {}
59
+ end
60
+ end
61
+
62
+ module MigrationMethods
63
+
64
+ def create_skr_table(table_name, *args, &block)
65
+ definition = nil
66
+ create_table( Skr.config.table_prefix + table_name, *args ) do | td |
67
+ # Thanks for the trick from the Foreigner gem!
68
+ # in connection_adapters/abstract/schema_statements
69
+ definition = td
70
+ block.call(td) unless block.nil?
71
+ end
72
+ definition.skr_foreign_keys.each do |to_table, options |
73
+ skr_add_foreign_key( table_name, to_table, options )
74
+ end
75
+ definition.skr_extra_indexes.each do | index_column, options |
76
+ skr_add_index( table_name, index_column, options )
77
+ end
78
+ end
79
+
80
+ def skr_add_index( table_name, columns, options={} )
81
+ table_name = Skr.config.table_prefix + table_name.to_s
82
+ if options[:function]
83
+ unique = options[:unique] ? 'unique' : ''
84
+ name = table_name + 'indx_' + columns
85
+ execute( "create #{unique} index #{name} on #{table_name}(#{options[:function]})" )
86
+ else
87
+ add_index( table_name, columns, options )
88
+ end
89
+ end
90
+
91
+ def skr_add_foreign_key( table_name, to_table, options = {} )
92
+ from_table = Skr.config.table_prefix + table_name.to_s
93
+ to_table = Skr.config.table_prefix + to_table.to_s
94
+
95
+ column = options[:column] || "#{to_table.to_s.singularize}_id"
96
+ foreign_key_name = options.key?(:name) ? options[:name].to_s : "#{from_table}_#{column}_fk"
97
+
98
+ primary_key = options[:primary_key] || "id"
99
+ dependency = case options[:dependent]
100
+ when :nullify then "ON DELETE SET NULL"
101
+ when :delete then "ON DELETE CASCADE"
102
+ when :restrict then "ON DELETE RESTRICT"
103
+ else ""
104
+ end
105
+ sql = "ALTER TABLE #{quote_table_name(from_table)} " +
106
+ "ADD CONSTRAINT #{quote_column_name(foreign_key_name)} " +
107
+ "FOREIGN KEY (#{quote_column_name(column)}) " +
108
+ "REFERENCES #{quote_table_name( to_table )}(#{primary_key})"
109
+ sql << " #{dependency}" if dependency.present?
110
+ sql << " #{options[:options]}" if options[:options]
111
+
112
+ execute(sql)
113
+ end
114
+
115
+ def drop_skr_table( table_name, *args )
116
+ drop_table( Skr.config.table_prefix + table_name )
117
+ end
118
+
119
+ def remove_skr_index( table_name, column )
120
+ remove_index( Skr.config.table_prefix + table_name, column )
121
+ end
122
+
123
+ end
124
+
125
+ module CommandRecorder
126
+ def create_skr_table(*args)
127
+ record(:create_skr_table, args)
128
+ end
129
+
130
+ def drop_skr_table(*args)
131
+ record(:drop_skr_table, args)
132
+ end
133
+
134
+ def invert_create_skr_table(args)
135
+ from_table, to_table, add_options = *args
136
+ add_options ||= {}
137
+ if add_options[:name]
138
+ options = {name: add_options[:name]}
139
+ elsif add_options[:column]
140
+ options = {column: add_options[:column]}
141
+ else
142
+ options = to_table
143
+ end
144
+ [:drop_skr_table, [from_table, options]]
145
+ end
146
+
147
+ def skr_add_index(*args)
148
+ record(:skr_add_index,args)
149
+ end
150
+ def invert_skr_add_index(args)
151
+ table, column = *args
152
+ [:remove_skr_index, [table, column]]
153
+ end
154
+
155
+ end
156
+
157
+ end
158
+
159
+ end
160
+
161
+
162
+ class ActiveRecord::Migration
163
+ def skr_prefix
164
+ Skr.config.table_prefix
165
+ end
166
+ end
167
+
168
+ ActiveRecord::Migration::CommandRecorder.class_eval do
169
+ include Skr::DB::CommandRecorder
170
+ end
171
+
172
+ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
173
+ include Skr::DB::MigrationMethods
174
+ end
175
+
176
+ ActiveRecord::ConnectionAdapters::TableDefinition.class_eval do
177
+ include Skr::DB::TableFields
178
+ end
@@ -0,0 +1,23 @@
1
+ require 'lanes/access/extension'
2
+
3
+ module Skr
4
+
5
+ class Extension < Lanes::Extensions::Definition
6
+
7
+ identifier "skr"
8
+ self.uses_pub_sub = true
9
+ root_path Pathname.new(__FILE__).dirname.join("..","..").expand_path
10
+ components "record-finder", "select-field"
11
+
12
+ def on_boot
13
+ Lanes::API::Root.before do
14
+ Thread.current[:demo_user_info] = {
15
+ name: session[:name],
16
+ email: session[:email]
17
+ }
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ end
data/lib/skr/model.rb ADDED
@@ -0,0 +1,19 @@
1
+ module Skr
2
+
3
+ class Model < Lanes::Model
4
+ self.abstract_class = true
5
+
6
+ include Concerns::ActsAsUOM
7
+ include Concerns::StateMachine
8
+ include Concerns::HasSkuLocLines
9
+ include Concerns::HasGlTransaction
10
+ include Concerns::IsOrderLike
11
+ include Concerns::IsSkuLocLine
12
+ include Concerns::ImmutableModel
13
+ include Concerns::VisibleIdIdentifier
14
+ include Concerns::LockedFields
15
+ include Concerns::CodeIdentifier
16
+ include Concerns::RandomHashCode
17
+ end
18
+
19
+ end
@@ -0,0 +1,97 @@
1
+ module Skr
2
+
3
+ # A postal address with optional email and phone number
4
+ # By default all fields may be left blank.
5
+ #
6
+ # Validations may be selectively enabled by using the #enable_validations method
7
+ class Address < Skr::Model
8
+
9
+ # @!attribute email
10
+ # The email address to use
11
+
12
+ # @!attribute ensure_not_blank
13
+ # Must the Address be filled out? The {#blank?} method must return false
14
+ # @return [Boolean]
15
+ # @!attribute validate_email
16
+ # Will the email be validated to meet the {EmailValidator} requirements?
17
+ # @return [Boolean]
18
+ # @!attribute validate_phone
19
+ # Should the phone field be validated to be not blank?
20
+ # @return [Boolean]
21
+ attr_accessor :ensure_not_blank, :validate_email, :validate_phone
22
+
23
+ validates :name, :line1, :city, :state, :postal_code, :presence=>true, :if=>:ensure_not_blank
24
+ validates :email, :presence=>true, :email=>true, :if=>:validate_email
25
+ validates :phone, :presence=>true, :if=>:validate_phone
26
+
27
+ # @return [Address] a blank copy of an address
28
+ def self.blank
29
+ Address.new({ name: '', line1: '', city: '', state: '', postal_code: '' })
30
+ end
31
+
32
+ # @return [String] the name and email formatted for inclusion in an email
33
+ def email_with_name
34
+ "#{name} <#{email}>"
35
+ end
36
+
37
+ # fill in missing fields from postal_code using the ZipCode lookup table
38
+ def fill_missing_from_zip
39
+ if ( self.postal_code.present? &&
40
+ ( self.city.blank? || self.state.blank? ) &&
41
+ zc = ZipCode.find_by_code( self.postal_code )
42
+ )
43
+ self.city ||= zc.city
44
+ self.state ||= zc.state
45
+ end
46
+ end
47
+
48
+ # @return [Boolean] is any of (name line1 city state postal_code) blank?
49
+ def blank?
50
+ return !! %w{ name line1 city state postal_code }.detect{ |field| self[field].blank? }
51
+ end
52
+
53
+ # split the name on space
54
+ # @return [Hash]
55
+ # * :first [String] Portion of name before first space
56
+ # * :last [String] Portion of name after last space
57
+ def seperated_name
58
+ {:first=>name.to_s.split(' ').first, :last=> name.to_s.split(' ').last }
59
+ end
60
+
61
+ # enable selected validations
62
+ # @option options [Boolean] :include_email should the email be validated
63
+ # @option options [Boolean] :include_phone should the phone number be validated
64
+ def enable_validations( options = {} )
65
+ self.ensure_not_blank = true
66
+ self.validate_email = options[:include_email]
67
+ self.validate_phone = options[:include_phone]
68
+ end
69
+
70
+ # @param include [Array] list of extra fields to include in the address
71
+ # @return [String] Address converted to string, formatted with line breaks in the typical US style of display
72
+ # @example
73
+ # address = Address.new( name: 'Bob\s Uncle',phone: '877-555-5555', line1: 'PO Box 87',
74
+ # city: 'Nowhereville', state: 'Urgandishly' postal_code: 'ASCN 1ZZ' )
75
+ # address.to_s( :include => :phone ) #=>
76
+ # Bob's Uncle
77
+ # PO Box 87
78
+ # Nowhereville, Urgandishly ASCN 1ZZ
79
+ # 877-5550-5555
80
+ def to_s( include: [] )
81
+ ret = ""
82
+ %w{ name line1 line2 }.each{ |a| ret << self[a] + "\n" unless self[a].blank? }
83
+ ret << city.to_s
84
+ ret << ' ' + state unless state.blank?
85
+ ret << ', ' + postal_code.to_s unless postal_code.blank?
86
+ include = [ *include ]
87
+ if include.any?
88
+ ret << "\n" + include.map{ | field | self[ field ] }.join(' ')
89
+ end
90
+ ret
91
+ end
92
+
93
+
94
+ end
95
+
96
+
97
+ end # end Skr module