stockor 0.1.5

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