stockor 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +220 -0
- data/Guardfile +13 -0
- data/README.md +7 -0
- data/Rakefile +7 -0
- data/client/skr/Extension.coffee +12 -0
- data/client/skr/components/.gitkeep +0 -0
- data/client/skr/components/address/Address.coffee +21 -0
- data/client/skr/components/address/address.html +20 -0
- data/client/skr/index.js +21 -0
- data/client/skr/models/Address.coffee +17 -0
- data/client/skr/models/Base.coffee +8 -0
- data/client/skr/models/Customer.coffee +26 -0
- data/client/skr/models/GlAccount.coffee +10 -0
- data/client/skr/models/GlManualEntry.coffee +11 -0
- data/client/skr/models/GlPeriod.coffee +10 -0
- data/client/skr/models/GlPosting.coffee +15 -0
- data/client/skr/models/GlTransaction.coffee +16 -0
- data/client/skr/models/IaLine.coffee +19 -0
- data/client/skr/models/IaReason.coffee +12 -0
- data/client/skr/models/InvLine.coffee +27 -0
- data/client/skr/models/InventoryAdjustment.coffee +17 -0
- data/client/skr/models/Invoice.coffee +31 -0
- data/client/skr/models/Location.coffee +15 -0
- data/client/skr/models/PaymentTerm.coffee +11 -0
- data/client/skr/models/PickTicket.coffee +19 -0
- data/client/skr/models/PoLine.coffee +27 -0
- data/client/skr/models/PoReceipt.coffee +20 -0
- data/client/skr/models/PorLine.coffee +26 -0
- data/client/skr/models/PtLine.coffee +27 -0
- data/client/skr/models/PurchaseOrder.coffee +23 -0
- data/client/skr/models/SalesOrder.coffee +32 -0
- data/client/skr/models/Sku.coffee +21 -0
- data/client/skr/models/SkuLoc.coffee +21 -0
- data/client/skr/models/SkuTran.coffee +23 -0
- data/client/skr/models/SkuVendor.coffee +19 -0
- data/client/skr/models/SoLine.coffee +27 -0
- data/client/skr/models/Uom.coffee +17 -0
- data/client/skr/models/Vendor.coffee +28 -0
- data/client/skr/models/VoLine.coffee +23 -0
- data/client/skr/models/Voucher.coffee +22 -0
- data/client/skr/models/mixins/CodeField.coffee +5 -0
- data/client/skr/screens/.gitkeep +0 -0
- data/client/skr/screens/Base.coffee +3 -0
- data/client/skr/screens/base/index.js +5 -0
- data/client/skr/screens/base/index.scss +9 -0
- data/client/skr/screens/base/layout.html +3 -0
- data/client/skr/screens/customer-maint/CustomerMaint.coffee +49 -0
- data/client/skr/screens/customer-maint/index.js +5 -0
- data/client/skr/screens/customer-maint/index.scss +9 -0
- data/client/skr/screens/customer-maint/layout.html +32 -0
- data/client/skr/styles.scss +1 -0
- data/client/skr/views/.gitkeep +0 -0
- data/client/skr/views/Base.coffee +5 -0
- data/config/database.yml +9 -0
- data/config/lanes.rb +7 -0
- data/config/routes.rb +39 -0
- data/config/screens.rb +17 -0
- data/config.ru +5 -0
- data/db/.gitkeep +0 -0
- data/db/migrate/20120110142845_create_skr_sequential_ids.rb +35 -0
- data/db/migrate/20140202185309_create_skr_gl_accounts.rb +15 -0
- data/db/migrate/20140202193316_create_skr_gl_periods.rb +16 -0
- data/db/migrate/20140202193318_create_skr_gl_transactions.rb +14 -0
- data/db/migrate/20140202193319_create_skr_gl_postings.rb +16 -0
- data/db/migrate/20140202193700_create_skr_gl_manual_entries.rb +13 -0
- data/db/migrate/20140213040608_create_skr_payment_terms.rb +16 -0
- data/db/migrate/20140220031700_create_skr_addresses.rb +19 -0
- data/db/migrate/20140220031800_create_skr_locations.rb +19 -0
- data/db/migrate/20140220190836_create_skr_vendors.rb +22 -0
- data/db/migrate/20140220203029_create_skr_customers.rb +22 -0
- data/db/migrate/20140224034759_create_skr_skus.rb +22 -0
- data/db/migrate/20140225032853_create_skr_sku_locs.rb +21 -0
- data/db/migrate/20140320030501_create_skr_uoms.rb +19 -0
- data/db/migrate/20140321031604_create_skr_sku_vendors.rb +18 -0
- data/db/migrate/20140322012143_create_skr_ia_reasons.rb +14 -0
- data/db/migrate/20140322014401_create_skr_inventory_adjustments.rb +16 -0
- data/db/migrate/20140322023453_create_skr_ia_lines.rb +18 -0
- data/db/migrate/20140322035024_create_skr_sku_trans.rb +21 -0
- data/db/migrate/20140322223912_create_skr_sales_orders.rb +27 -0
- data/db/migrate/20140322223920_create_skr_so_lines.rb +25 -0
- data/db/migrate/20140323001446_create_so_details_view.rb +81 -0
- data/db/migrate/20140327202102_create_skr_purchase_orders.rb +20 -0
- data/db/migrate/20140327202107_create_skr_po_lines.rb +25 -0
- data/db/migrate/20140327202207_create_skr_pick_tickets.rb +16 -0
- data/db/migrate/20140327202209_create_skr_pt_lines.rb +23 -0
- data/db/migrate/20140327224000_create_skr_invoices.rb +25 -0
- data/db/migrate/20140327224002_create_skr_inv_lines.rb +23 -0
- data/db/migrate/20140330232808_create_skr_sku_loc_details_view.rb +31 -0
- data/db/migrate/20140330232810_create_skr_sku_qty_details_view.rb +48 -0
- data/db/migrate/20140400164729_create_skr_vouchers.rb +22 -0
- data/db/migrate/20140400164733_create_skr_vo_lines.rb +21 -0
- data/db/migrate/20140401164729_create_skr_po_receipt.rb +16 -0
- data/db/migrate/20140401164740_create_skr_por_line.rb +21 -0
- data/db/migrate/20140422024010_create_skr_inv_details_view.rb +42 -0
- data/db/schema.sql +2662 -0
- data/db/seed/chart_of_accounts.yml +168 -0
- data/db/seed/payment_terms.yml +60 -0
- data/db/seed.rb +29 -0
- data/lib/skr/access_roles.rb +28 -0
- data/lib/skr/concerns/acts_as_uom.rb +47 -0
- data/lib/skr/concerns/code_identifier.rb +43 -0
- data/lib/skr/concerns/gl_tran_extensions.rb +18 -0
- data/lib/skr/concerns/has_gl_transaction.rb +67 -0
- data/lib/skr/concerns/has_sku_loc_lines.rb +47 -0
- data/lib/skr/concerns/immutable_model.rb +32 -0
- data/lib/skr/concerns/inv_extensions.rb +24 -0
- data/lib/skr/concerns/is_order_like.rb +47 -0
- data/lib/skr/concerns/is_sku_loc_line.rb +65 -0
- data/lib/skr/concerns/locked_fields.rb +84 -0
- data/lib/skr/concerns/pt_extensions.rb +22 -0
- data/lib/skr/concerns/random_hash_code.rb +40 -0
- data/lib/skr/concerns/so_extensions.rb +30 -0
- data/lib/skr/concerns/state_machine.rb +61 -0
- data/lib/skr/concerns/visible_id_identifier.rb +53 -0
- data/lib/skr/configuration.rb +68 -0
- data/lib/skr/db/migration_helpers.rb +178 -0
- data/lib/skr/extension.rb +23 -0
- data/lib/skr/model.rb +19 -0
- data/lib/skr/models/address.rb +97 -0
- data/lib/skr/models/business_entity.rb +29 -0
- data/lib/skr/models/customer.rb +35 -0
- data/lib/skr/models/gl_account.rb +56 -0
- data/lib/skr/models/gl_manual_entry.rb +31 -0
- data/lib/skr/models/gl_period.rb +13 -0
- data/lib/skr/models/gl_posting.rb +54 -0
- data/lib/skr/models/gl_transaction.rb +175 -0
- data/lib/skr/models/ia_line.rb +129 -0
- data/lib/skr/models/ia_reason.rb +16 -0
- data/lib/skr/models/inv_line.rb +90 -0
- data/lib/skr/models/inventory_adjustment.rb +60 -0
- data/lib/skr/models/invoice.rb +159 -0
- data/lib/skr/models/location.rb +31 -0
- data/lib/skr/models/payment_term.rb +30 -0
- data/lib/skr/models/pick_ticket.rb +71 -0
- data/lib/skr/models/po_line.rb +69 -0
- data/lib/skr/models/po_receipt.rb +51 -0
- data/lib/skr/models/por_line.rb +80 -0
- data/lib/skr/models/pt_line.rb +74 -0
- data/lib/skr/models/purchase_order.rb +112 -0
- data/lib/skr/models/sales_order.rb +159 -0
- data/lib/skr/models/sequential_id.rb +23 -0
- data/lib/skr/models/sku.rb +99 -0
- data/lib/skr/models/sku_loc.rb +94 -0
- data/lib/skr/models/sku_tran.rb +111 -0
- data/lib/skr/models/sku_vendor.rb +26 -0
- data/lib/skr/models/so_line.rb +159 -0
- data/lib/skr/models/uom.rb +63 -0
- data/lib/skr/models/user_proxy.rb +60 -0
- data/lib/skr/models/vendor.rb +33 -0
- data/lib/skr/models/vo_line.rb +35 -0
- data/lib/skr/models/voucher.rb +119 -0
- data/lib/skr/standard_pricing_provider.rb +14 -0
- data/lib/skr/version.rb +3 -0
- data/lib/skr.rb +18 -0
- data/lib/stockor.rb +4 -0
- data/lib/tasks/debug-activity.rake +58 -0
- data/log/test.log +0 -0
- data/spec/fixtures/skr/address.yml +2 -0
- data/spec/fixtures/skr/customer.yml +2 -0
- data/spec/fixtures/skr/gl_account.yml +2 -0
- data/spec/fixtures/skr/gl_manual_entry.yml +2 -0
- data/spec/fixtures/skr/gl_period.yml +2 -0
- data/spec/fixtures/skr/gl_posting.yml +2 -0
- data/spec/fixtures/skr/gl_transaction.yml +2 -0
- data/spec/fixtures/skr/ia_line.yml +2 -0
- data/spec/fixtures/skr/ia_reason.yml +2 -0
- data/spec/fixtures/skr/inv_line.yml +2 -0
- data/spec/fixtures/skr/inventory_adjustment.yml +2 -0
- data/spec/fixtures/skr/invoice.yml +2 -0
- data/spec/fixtures/skr/location.yml +2 -0
- data/spec/fixtures/skr/payment_term.yml +2 -0
- data/spec/fixtures/skr/pick_ticket.yml +2 -0
- data/spec/fixtures/skr/po_line.yml +2 -0
- data/spec/fixtures/skr/po_receipt.yml +2 -0
- data/spec/fixtures/skr/por_line.yml +2 -0
- data/spec/fixtures/skr/pt_line.yml +2 -0
- data/spec/fixtures/skr/purchase_order.yml +2 -0
- data/spec/fixtures/skr/sales_order.yml +2 -0
- data/spec/fixtures/skr/sku.yml +2 -0
- data/spec/fixtures/skr/sku_loc.yml +2 -0
- data/spec/fixtures/skr/sku_tran.yml +2 -0
- data/spec/fixtures/skr/sku_vendor.yml +2 -0
- data/spec/fixtures/skr/so_line.yml +2 -0
- data/spec/fixtures/skr/uom.yml +2 -0
- data/spec/fixtures/skr/vendor.yml +2 -0
- data/spec/fixtures/skr/vo_line.yml +2 -0
- data/spec/fixtures/skr/voucher.yml +2 -0
- data/spec/skr/address.rb +10 -0
- data/spec/skr/concerns/code_identifier_spec.rb +45 -0
- data/spec/skr/customer.rb +10 -0
- data/spec/skr/gl_account.rb +10 -0
- data/spec/skr/gl_manual_entry.rb +10 -0
- data/spec/skr/gl_period.rb +10 -0
- data/spec/skr/gl_posting.rb +10 -0
- data/spec/skr/gl_transaction.rb +10 -0
- data/spec/skr/ia_line.rb +10 -0
- data/spec/skr/ia_reason.rb +10 -0
- data/spec/skr/inv_line.rb +10 -0
- data/spec/skr/inventory_adjustment.rb +10 -0
- data/spec/skr/invoice.rb +10 -0
- data/spec/skr/location.rb +10 -0
- data/spec/skr/models/AddressSpec.coffee +5 -0
- data/spec/skr/models/CustomerSpec.coffee +5 -0
- data/spec/skr/models/GlAccountSpec.coffee +5 -0
- data/spec/skr/models/GlManualEntrySpec.coffee +5 -0
- data/spec/skr/models/GlPeriodSpec.coffee +5 -0
- data/spec/skr/models/GlPostingSpec.coffee +5 -0
- data/spec/skr/models/GlTransactionSpec.coffee +5 -0
- data/spec/skr/models/IaLineSpec.coffee +5 -0
- data/spec/skr/models/IaReasonSpec.coffee +5 -0
- data/spec/skr/models/InvLineSpec.coffee +5 -0
- data/spec/skr/models/InventoryAdjustmentSpec.coffee +5 -0
- data/spec/skr/models/InvoiceSpec.coffee +5 -0
- data/spec/skr/models/LocationSpec.coffee +5 -0
- data/spec/skr/models/PaymentTermSpec.coffee +5 -0
- data/spec/skr/models/PickTicketSpec.coffee +5 -0
- data/spec/skr/models/PoLineSpec.coffee +5 -0
- data/spec/skr/models/PoReceiptSpec.coffee +5 -0
- data/spec/skr/models/PorLineSpec.coffee +5 -0
- data/spec/skr/models/PtLineSpec.coffee +5 -0
- data/spec/skr/models/PurchaseOrderSpec.coffee +5 -0
- data/spec/skr/models/SalesOrderSpec.coffee +5 -0
- data/spec/skr/models/SkuLocSpec.coffee +5 -0
- data/spec/skr/models/SkuSpec.coffee +5 -0
- data/spec/skr/models/SkuTranSpec.coffee +5 -0
- data/spec/skr/models/SkuVendorSpec.coffee +5 -0
- data/spec/skr/models/SoLineSpec.coffee +5 -0
- data/spec/skr/models/UomSpec.coffee +5 -0
- data/spec/skr/models/VendorSpec.coffee +5 -0
- data/spec/skr/models/VoLineSpec.coffee +5 -0
- data/spec/skr/models/VoucherSpec.coffee +5 -0
- data/spec/skr/payment_term.rb +10 -0
- data/spec/skr/pick_ticket.rb +10 -0
- data/spec/skr/po_line.rb +10 -0
- data/spec/skr/po_receipt.rb +10 -0
- data/spec/skr/por_line.rb +10 -0
- data/spec/skr/pt_line.rb +10 -0
- data/spec/skr/purchase_order.rb +10 -0
- data/spec/skr/sales_order.rb +10 -0
- data/spec/skr/screens/Base.coffee +7 -0
- data/spec/skr/screens/CustomerMaint.coffee +7 -0
- data/spec/skr/screens/vendor-maint/VendorMaintSpec.coffee +5 -0
- data/spec/skr/sku.rb +10 -0
- data/spec/skr/sku_loc.rb +10 -0
- data/spec/skr/sku_tran.rb +10 -0
- data/spec/skr/sku_vendor.rb +10 -0
- data/spec/skr/so_line.rb +10 -0
- data/spec/skr/spec_helper.rb +26 -0
- data/spec/skr/uom.rb +10 -0
- data/spec/skr/vendor.rb +10 -0
- data/spec/skr/views/AddressSpec.coffee +5 -0
- data/spec/skr/vo_line.rb +10 -0
- data/spec/skr/voucher.rb +10 -0
- data/stockor.gemspec +38 -0
- data/tmp/.gitkeep +0 -0
- 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
|