stockor-core 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +6 -0
- data/Guardfile +13 -0
- data/LICENSE.txt +674 -0
- data/README.md +88 -0
- data/Rakefile +58 -0
- data/config/database.yml +9 -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/lib/generators/stockor/migrations/install_generator.rb +42 -0
- data/lib/skr/address.rb +97 -0
- data/lib/skr/business_entity.rb +25 -0
- data/lib/skr/concerns/acts_as_uom.rb +47 -0
- data/lib/skr/concerns/all.rb +30 -0
- data/lib/skr/concerns/association_extensions.rb +85 -0
- data/lib/skr/concerns/attr_accessor_with_default.rb +54 -0
- data/lib/skr/concerns/code_identifier.rb +43 -0
- data/lib/skr/concerns/export_associations.rb +52 -0
- data/lib/skr/concerns/export_join_tables.rb +39 -0
- data/lib/skr/concerns/export_methods.rb +104 -0
- data/lib/skr/concerns/export_scope.rb +66 -0
- data/lib/skr/concerns/exported_limit_evaluator.rb +17 -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/json_attribute_access.rb +55 -0
- data/lib/skr/concerns/locked_fields.rb +84 -0
- data/lib/skr/concerns/pt_extensions.rb +22 -0
- data/lib/skr/concerns/pub_sub.rb +105 -0
- data/lib/skr/concerns/queries.rb +20 -0
- data/lib/skr/concerns/random_hash_code.rb +40 -0
- data/lib/skr/concerns/sanitize_json.rb +49 -0
- data/lib/skr/concerns/sku_extensions.rb +52 -0
- data/lib/skr/concerns/so_extensions.rb +30 -0
- data/lib/skr/concerns/state_machine.rb +62 -0
- data/lib/skr/concerns/track_modifications.rb +48 -0
- data/lib/skr/concerns/visible_id_identifier.rb +53 -0
- data/lib/skr/core.rb +30 -0
- data/lib/skr/core/configuration.rb +87 -0
- data/lib/skr/core/db.rb +82 -0
- data/lib/skr/core/db/migration_helpers.rb +178 -0
- data/lib/skr/core/db/migrations.rb +15 -0
- data/lib/skr/core/db/seed.rb +46 -0
- data/lib/skr/core/db/seed/chart_of_accounts.yml +168 -0
- data/lib/skr/core/db/seed/payment_terms.yml +60 -0
- data/lib/skr/core/logger.rb +36 -0
- data/lib/skr/core/numbers.rb +71 -0
- data/lib/skr/core/rails_engine.rb +5 -0
- data/lib/skr/core/standard_pricing_provider.rb +15 -0
- data/lib/skr/core/strings.rb +57 -0
- data/lib/skr/core/testing.rb +11 -0
- data/lib/skr/core/testing/assertions.rb +44 -0
- data/lib/skr/core/testing/fixtures.rb +25 -0
- data/lib/skr/core/testing/fixtures/skr/addresses.yml +53 -0
- data/lib/skr/core/testing/fixtures/skr/customers.yml +43 -0
- data/lib/skr/core/testing/fixtures/skr/gl_accounts.yml +86 -0
- data/lib/skr/core/testing/fixtures/skr/gl_manual_entries.yml +4 -0
- data/lib/skr/core/testing/fixtures/skr/gl_periods.yml +26 -0
- data/lib/skr/core/testing/fixtures/skr/gl_postings.yml +88 -0
- data/lib/skr/core/testing/fixtures/skr/gl_transactions.yml +35 -0
- data/lib/skr/core/testing/fixtures/skr/ia_lines.yml +7 -0
- data/lib/skr/core/testing/fixtures/skr/ia_reasons.yml +15 -0
- data/lib/skr/core/testing/fixtures/skr/inv_lines.yml +22 -0
- data/lib/skr/core/testing/fixtures/skr/inventory_adjustments.yml +6 -0
- data/lib/skr/core/testing/fixtures/skr/invoices.yml +10 -0
- data/lib/skr/core/testing/fixtures/skr/locations.yml +24 -0
- data/lib/skr/core/testing/fixtures/skr/payment_terms.yml +42 -0
- data/lib/skr/core/testing/fixtures/skr/pick_tickets.yml +4 -0
- data/lib/skr/core/testing/fixtures/skr/po_lines.yml +44 -0
- data/lib/skr/core/testing/fixtures/skr/po_receipts.yml +5 -0
- data/lib/skr/core/testing/fixtures/skr/por_lines.yml +13 -0
- data/lib/skr/core/testing/fixtures/skr/pt_lines.yml +12 -0
- data/lib/skr/core/testing/fixtures/skr/purchase_orders.yml +16 -0
- data/lib/skr/core/testing/fixtures/skr/sales_orders.yml +32 -0
- data/lib/skr/core/testing/fixtures/skr/sku_locs.yml +78 -0
- data/lib/skr/core/testing/fixtures/skr/sku_trans.yml +9 -0
- data/lib/skr/core/testing/fixtures/skr/sku_vendors.yml +35 -0
- data/lib/skr/core/testing/fixtures/skr/skus.yml +50 -0
- data/lib/skr/core/testing/fixtures/skr/so_lines.yml +71 -0
- data/lib/skr/core/testing/fixtures/skr/uoms.yml +61 -0
- data/lib/skr/core/testing/fixtures/skr/vendors.yml +48 -0
- data/lib/skr/core/testing/fixtures/skr/vo_lines.yml +12 -0
- data/lib/skr/core/testing/fixtures/skr/vouchers.yml +8 -0
- data/lib/skr/core/testing/helper.rb +18 -0
- data/lib/skr/core/testing/test_case.rb +17 -0
- data/lib/skr/core/version.rb +5 -0
- data/lib/skr/customer.rb +34 -0
- data/lib/skr/gl_account.rb +56 -0
- data/lib/skr/gl_manual_entry.rb +31 -0
- data/lib/skr/gl_period.rb +13 -0
- data/lib/skr/gl_posting.rb +54 -0
- data/lib/skr/gl_transaction.rb +174 -0
- data/lib/skr/ia_line.rb +129 -0
- data/lib/skr/ia_reason.rb +16 -0
- data/lib/skr/inv_line.rb +90 -0
- data/lib/skr/inventory_adjustment.rb +60 -0
- data/lib/skr/invoice.rb +159 -0
- data/lib/skr/location.rb +31 -0
- data/lib/skr/model.rb +37 -0
- data/lib/skr/null_user.rb +30 -0
- data/lib/skr/payment_term.rb +30 -0
- data/lib/skr/pick_ticket.rb +71 -0
- data/lib/skr/po_line.rb +69 -0
- data/lib/skr/po_receipt.rb +51 -0
- data/lib/skr/por_line.rb +80 -0
- data/lib/skr/pt_line.rb +74 -0
- data/lib/skr/purchase_order.rb +112 -0
- data/lib/skr/sales_order.rb +159 -0
- data/lib/skr/sequential_id.rb +23 -0
- data/lib/skr/sku.rb +99 -0
- data/lib/skr/sku_loc.rb +94 -0
- data/lib/skr/sku_tran.rb +111 -0
- data/lib/skr/sku_vendor.rb +26 -0
- data/lib/skr/so_line.rb +159 -0
- data/lib/skr/uom.rb +63 -0
- data/lib/skr/user_proxy.rb +60 -0
- data/lib/skr/validators/all.rb +2 -0
- data/lib/skr/validators/email.rb +17 -0
- data/lib/skr/validators/set.rb +18 -0
- data/lib/skr/vendor.rb +33 -0
- data/lib/skr/vo_line.rb +35 -0
- data/lib/skr/voucher.rb +119 -0
- data/lib/stockor/core.rb +9 -0
- data/stockor-core.gemspec +37 -0
- data/tasks/migrations.rake +23 -0
- data/tasks/publish.rake +8 -0
- data/test/address_test.rb +57 -0
- data/test/concerns/attr_with_default_test.rb +45 -0
- data/test/concerns/code_identifier_test.rb +46 -0
- data/test/concerns/export_associations_test.rb +7 -0
- data/test/concerns/export_methods_test.rb +31 -0
- data/test/concerns/export_scope_test.rb +16 -0
- data/test/concerns/exported_limits_test.rb +47 -0
- data/test/concerns/json_attribute_access_test.rb +27 -0
- data/test/concerns/pub_sub_test.rb +83 -0
- data/test/concerns/sanitize_json_test.rb +47 -0
- data/test/core/configuration_test.rb +24 -0
- data/test/core/numbers_test.rb +26 -0
- data/test/core/strings_test.rb +41 -0
- data/test/customer_test.rb +34 -0
- data/test/gl_account_test.rb +23 -0
- data/test/gl_manual_entry_test.rb +17 -0
- data/test/gl_period_test.rb +12 -0
- data/test/gl_posting_test.rb +39 -0
- data/test/gl_transaction_test.rb +58 -0
- data/test/ia_line_test.rb +68 -0
- data/test/ia_reason_test.rb +11 -0
- data/test/inv_line_test.rb +58 -0
- data/test/inventory_adjustment_test.rb +72 -0
- data/test/invoice_test.rb +63 -0
- data/test/location_test.rb +10 -0
- data/test/payment_term_test.rb +25 -0
- data/test/pick_ticket_test.rb +27 -0
- data/test/po_line_test.rb +36 -0
- data/test/po_receipt_test.rb +93 -0
- data/test/por_line_test.rb +79 -0
- data/test/pt_line_test.rb +29 -0
- data/test/purchase_order_test.rb +44 -0
- data/test/sales_order_test.rb +74 -0
- data/test/sku_loc_test.rb +50 -0
- data/test/sku_test.rb +45 -0
- data/test/sku_tran_test.rb +21 -0
- data/test/sku_vendor_test.rb +13 -0
- data/test/so_line_test.rb +89 -0
- data/test/test_helper.rb +1 -0
- data/test/uom_test.rb +14 -0
- data/test/vendor_test.rb +35 -0
- data/test/vo_line_test.rb +20 -0
- data/test/voucher_test.rb +35 -0
- data/yard_ext/all.rb +9 -0
- data/yard_ext/code_identifier_handler.rb +33 -0
- data/yard_ext/concern_meta_methods.rb +60 -0
- data/yard_ext/config_options.rb +27 -0
- data/yard_ext/exported_scope.rb +4 -0
- data/yard_ext/immutable_handler.rb +17 -0
- data/yard_ext/json_attr_accessor.rb +22 -0
- data/yard_ext/locked_fields_handler.rb +21 -0
- data/yard_ext/templates/default/layout/html/layout.erb +20 -0
- data/yard_ext/templates/default/method_details/html/github_link.erb +1 -0
- data/yard_ext/templates/default/method_details/setup.rb +3 -0
- data/yard_ext/validators.rb +1 -0
- data/yard_ext/visible_id_handler.rb +38 -0
- metadata +448 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
module Skr
|
2
|
+
module Concerns
|
3
|
+
|
4
|
+
module HasSkuLocLines
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module InstanceMethods
|
9
|
+
|
10
|
+
def other_charge_lines
|
11
|
+
self.lines.select{|l| l.sku.is_other_charge? }
|
12
|
+
end
|
13
|
+
|
14
|
+
def regular_lines
|
15
|
+
self.lines.reject{|l| l.sku.is_other_charge? }
|
16
|
+
end
|
17
|
+
|
18
|
+
def regular_lines_total
|
19
|
+
self.regular_lines.sum{|l|l.extended_price}
|
20
|
+
end
|
21
|
+
|
22
|
+
def subtotal
|
23
|
+
self.regular_lines.inject(0){|sum,line| sum + line.extended_price }
|
24
|
+
end
|
25
|
+
|
26
|
+
def total
|
27
|
+
if total = self.read_attribute('total')
|
28
|
+
BigDecimal.new(total)
|
29
|
+
elsif self.new_record? || self.association(:lines).loaded?
|
30
|
+
self.lines.inject( BigDecimal.new('0') ){|sum,line| sum += line.extended_price }
|
31
|
+
else
|
32
|
+
BigDecimal.new( self.lines.sum('price*qty') )
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module ClassMethods
|
38
|
+
|
39
|
+
def has_sku_loc_lines
|
40
|
+
self.send :include, InstanceMethods
|
41
|
+
export_methods :total
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Skr
|
2
|
+
module Concerns
|
3
|
+
|
4
|
+
module ImmutableModel
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
# Once it's created it may not be updated or destroyed.
|
11
|
+
# @raise [ActiveRecord::ReadOnlyRecord] if destroy, delete or save is called after it's been created.
|
12
|
+
def is_immutable(options = {})
|
13
|
+
|
14
|
+
options[:except] = [*options[:except]].map{|name| name.to_s } # make sure except is present and an array
|
15
|
+
|
16
|
+
before_destroy do
|
17
|
+
raise ActiveRecord::ReadOnlyRecord.new( "Can not destroy #{self.class.model_name}, only create is allowed" )
|
18
|
+
end
|
19
|
+
|
20
|
+
before_update do
|
21
|
+
unless ( changes.keys - change_tracking_fields - options[:except] ).blank?
|
22
|
+
raise ActiveRecord::ReadOnlyRecord.new( "Can not update, only create #{self.class.model_name}" )
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Skr
|
2
|
+
module Concerns
|
3
|
+
|
4
|
+
module INV
|
5
|
+
|
6
|
+
module Lines
|
7
|
+
|
8
|
+
def from_pick_ticket!
|
9
|
+
proxy_association.owner.pick_ticket.lines.each do | line |
|
10
|
+
build({ pt_line: line, qty: line.qty_to_ship })
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def from_sales_order!
|
15
|
+
proxy_association.owner.sales_order.lines.each do | line |
|
16
|
+
build({ so_line: line, qty: line.qty_allocated })
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Skr
|
2
|
+
module Concerns
|
3
|
+
|
4
|
+
module IsOrderLike
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module InstanceMethods
|
8
|
+
|
9
|
+
|
10
|
+
# Set's the customer. It also defaults the terms, addresses,and tax_exempt status to the customer's defaults
|
11
|
+
# @param cust [Customer]
|
12
|
+
# @return Customer
|
13
|
+
def customer=(cust)
|
14
|
+
super
|
15
|
+
self.terms ||= cust.terms
|
16
|
+
self.is_tax_exempt = cust.is_tax_exempt if self.is_tax_exempt.nil?
|
17
|
+
self.billing_address = cust.billing_address.dup unless self.billing_address.present?
|
18
|
+
self.shipping_address = cust.shipping_address.dup unless self.shipping_address.present?
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def set_order_defaults
|
24
|
+
self.location ||= Location.default
|
25
|
+
self.terms ||= customer.terms if self.customer
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
module ClassMethods
|
32
|
+
|
33
|
+
def is_order_like
|
34
|
+
self.send :include, InstanceMethods
|
35
|
+
has_sku_loc_lines # pull in the sku_loc_lines module
|
36
|
+
|
37
|
+
validates_associated :lines
|
38
|
+
|
39
|
+
before_validation :set_order_defaults, :on=>:create
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Skr
|
2
|
+
module Concerns
|
3
|
+
|
4
|
+
module IsSkuLocLine
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module InstanceMethods
|
9
|
+
def uom_record
|
10
|
+
if self.association(:sku).loaded? && self.sku.association(:uoms).loaded?
|
11
|
+
self.sku.uoms.detect{|uom| uom.code == self.uom_code }
|
12
|
+
else
|
13
|
+
self.sku.uoms.where({ code: self.uom_code }).first
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def ea_qty
|
18
|
+
self.qty*self.uom_size
|
19
|
+
end
|
20
|
+
|
21
|
+
def is_other_charge?
|
22
|
+
self.sku.is_other_charge?
|
23
|
+
end
|
24
|
+
|
25
|
+
def extended_price
|
26
|
+
self.price && self.qty ? self.price * self.qty : BigDecimal.new(0)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def ensure_sku_does_not_change
|
32
|
+
errors.add(:sku, "can not be updated") if changes['sku_code']
|
33
|
+
if change = changes['sku_loc_id']
|
34
|
+
# allow if the sku_id is the same on both old & new locations
|
35
|
+
unless 1 == SkuLoc.where( id: change ).pluck('sku_id').uniq.length
|
36
|
+
errors.add(:sku, "must be the same in both locations") if sku_code_changed?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module ClassMethods
|
43
|
+
|
44
|
+
def is_sku_loc_line( parent: nil )
|
45
|
+
self.send :include, InstanceMethods
|
46
|
+
|
47
|
+
validate :ensure_sku_does_not_change, :on=>:update
|
48
|
+
|
49
|
+
if parent
|
50
|
+
before_create do
|
51
|
+
self.position ||= ( self.send( parent ).lines.maximum(:position) || 0 ) + 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
export_methods :extended_price, :optional=>false
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Skr::Concerns
|
2
|
+
|
3
|
+
# @see ClassMethods
|
4
|
+
module JsonAttributeAccess
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_attribute :blacklisted_json_attributes
|
10
|
+
class_attribute :whitelisted_json_attributes
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
# An attribute accessor that allows access from the API
|
16
|
+
def json_attr_accessor( *names )
|
17
|
+
names.each do | attr |
|
18
|
+
attr_accessor attr
|
19
|
+
whitelist_json_attributes attr
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param attributes [Array of symbols] attributes that are safe for the API to set
|
24
|
+
def whitelist_json_attributes( *attributes )
|
25
|
+
options = attributes.extract_options!
|
26
|
+
self.whitelisted_json_attributes ||= {}
|
27
|
+
attributes.each{|attr| self.whitelisted_json_attributes[ attr.to_sym ] = options }
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param attributes [Array of symbols] attributes that are not safe for the API to set
|
31
|
+
def blacklist_json_attributes( *attributes )
|
32
|
+
options = attributes.extract_options!
|
33
|
+
self.blacklisted_json_attributes ||= {}
|
34
|
+
attributes.each{|attr| self.blacklisted_json_attributes[ attr.to_sym ] = options }
|
35
|
+
end
|
36
|
+
|
37
|
+
# An attribute is allowed if it's white listed
|
38
|
+
# or it's a valid attribute and not black listed
|
39
|
+
# @param name [Symbol]
|
40
|
+
# @param user [UserProxy,User] who is performing request
|
41
|
+
def json_attribute_is_allowed?(name, user = Skr::UserProxy.current)
|
42
|
+
return false unless user.can_write?(self, name)
|
43
|
+
(self.whitelisted_json_attributes && self.whitelisted_json_attributes.has_key?( name.to_sym)) ||
|
44
|
+
(
|
45
|
+
self.attribute_names.include?( name.to_s ) &&
|
46
|
+
( self.blacklisted_json_attributes.nil? ||
|
47
|
+
! self.blacklisted_json_attributes.has_key?( name.to_sym ) )
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -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,105 @@
|
|
1
|
+
module Skr::Concerns
|
2
|
+
|
3
|
+
module PendingEventListeners
|
4
|
+
# @private
|
5
|
+
@@listeners = Hash.new{ |hash, klass| hash[klass] = Hash.new{ |kh, event| kh[event]=Array.new } }
|
6
|
+
# @api private
|
7
|
+
def self.all
|
8
|
+
@@listeners
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
# Event subscription and publishing for Stockor Models
|
14
|
+
# Every model has certain built-in events (:save, :create, :update, :destroy)
|
15
|
+
# And may also implement custom events that reflect the models domain
|
16
|
+
# @example Send an email when a customer's name is updated
|
17
|
+
# Customer.observe(:update) do |customer|
|
18
|
+
# Mailer.notify_billing(customer).deliver if customer.name_changed?
|
19
|
+
# end
|
20
|
+
# @example Update some stats when a Sku's qty is changed
|
21
|
+
# Sku.observe(:qty_changed) do | sku, location, old_qty, new_qty |
|
22
|
+
# Stats.refresh( location )
|
23
|
+
# end
|
24
|
+
module PubSub
|
25
|
+
extend ActiveSupport::Concern
|
26
|
+
|
27
|
+
class InvalidEvent < RuntimeError
|
28
|
+
end
|
29
|
+
|
30
|
+
included do | base |
|
31
|
+
|
32
|
+
class_attribute :valid_event_names
|
33
|
+
class_attribute :_event_listeners
|
34
|
+
self.valid_event_names = [ :save, :create, :update, :destroy ]
|
35
|
+
|
36
|
+
after_save :fire_after_save_events
|
37
|
+
after_create :fire_after_create_events
|
38
|
+
after_update :fire_after_update_events
|
39
|
+
after_destroy :fire_after_destroy_events
|
40
|
+
end
|
41
|
+
|
42
|
+
module ClassMethods
|
43
|
+
def inherited(base)
|
44
|
+
super
|
45
|
+
klass = base.to_s.demodulize
|
46
|
+
if PendingEventListeners.all.has_key?( klass )
|
47
|
+
events = PendingEventListeners.all.delete(klass)
|
48
|
+
events.each{ | name, procs | base.event_listeners[name] += procs }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def event_listeners
|
53
|
+
self._event_listeners ||= Hash.new{ |hash, key| hash[key]=Array.new }
|
54
|
+
end
|
55
|
+
|
56
|
+
def _add_event_listener( name, proc )
|
57
|
+
self.event_listeners[name].push( proc ) unless self.event_listeners[name].include?(proc)
|
58
|
+
end
|
59
|
+
|
60
|
+
def observe( event, &block )
|
61
|
+
_ensure_validate_event( event )
|
62
|
+
_add_event_listener( event.to_sym, block )
|
63
|
+
end
|
64
|
+
|
65
|
+
def _ensure_validate_event(event)
|
66
|
+
unless self.valid_event_names.include?(event.to_sym)
|
67
|
+
raise InvalidEvent.new("#{event} is not a valid event for #{self}")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
def has_additional_events( *names )
|
74
|
+
self.valid_event_names += names.map{ |name| name.to_sym }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
def fire_after_destroy_events
|
80
|
+
_fire_event(:update, self )
|
81
|
+
end
|
82
|
+
def fire_after_update_events
|
83
|
+
_fire_event(:update, self )
|
84
|
+
end
|
85
|
+
def fire_after_create_events
|
86
|
+
_fire_event(:create, self )
|
87
|
+
end
|
88
|
+
def fire_after_save_events
|
89
|
+
_fire_event( :save, self )
|
90
|
+
end
|
91
|
+
|
92
|
+
def fire_event( name, *arguments )
|
93
|
+
self.class._ensure_validate_event( name )
|
94
|
+
arguments.unshift( self )
|
95
|
+
_fire_event( name, *arguments )
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
def _fire_event( name, *arguments )
|
100
|
+
self.class.event_listeners[ name.to_sym ].each{ | block | block.call(*arguments) }
|
101
|
+
return true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|