stockor-core 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|