Class: LandedCost
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- LandedCost
- Includes:
- Models::Auditable
- Defined in:
- app/models/landed_cost.rb
Overview
== Schema Information
Table name: landed_costs
Database name: primary
id :integer not null, primary key
currency :string(255)
estimated :boolean default(FALSE)
quantity :integer
state :string(255)
total_landed_cost :decimal(11, 5)
total_weight :float
unit_landed_cost :decimal(11, 5)
unit_weight :float
created_at :datetime
updated_at :datetime
carrier_id :integer
creator_id :integer
purchase_order_id :integer
purchase_order_item_id :integer
shipment_receipt_id :integer
shipment_receipt_item_id :integer
updater_id :integer
Indexes
idx_purchase_order_id (purchase_order_id)
poi_id_state_estimated (purchase_order_item_id,state,estimated)
sr_id_state_estimated (shipment_receipt_id,state,estimated)
sri_id_estimated (shipment_receipt_item_id,estimated)
state_sri_id (state,shipment_receipt_item_id)
Constant Summary
Constants included from Models::Auditable
Models::Auditable::ALWAYS_IGNORED
Instance Attribute Summary collapse
-
#quantity ⇒ Object
readonly
validates_numericality_of :unit_landed_cost, :total_landed_cost, :greater_than_or_equal_to => 0.
Belongs to collapse
- #carrier ⇒ Supplier
- #purchase_order ⇒ PurchaseOrder
- #purchase_order_item ⇒ PurchaseOrderItem
- #shipment_receipt ⇒ ShipmentReceipt
- #shipment_receipt_item ⇒ ShipmentReceiptItem
Methods included from Models::Auditable
Has many collapse
- #item_ledger_entries ⇒ ActiveRecord::Relation<ItemLedgerEntry>
- #ledger_transactions ⇒ ActiveRecord::Relation<LedgerTransaction>
Class Method Summary collapse
-
.active ⇒ ActiveRecord::Relation<LandedCost>
A relation of LandedCosts that are active.
-
.actual ⇒ ActiveRecord::Relation<LandedCost>
A relation of LandedCosts that are actual.
-
.estimated ⇒ ActiveRecord::Relation<LandedCost>
A relation of LandedCosts that are estimated.
Instance Method Summary collapse
Methods included from Models::Auditable
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Models::EventPublishable
Instance Attribute Details
#quantity ⇒ Object (readonly)
validates_numericality_of :unit_landed_cost, :total_landed_cost, :greater_than_or_equal_to => 0
Validations:
- Numericality ({ greater_than: 0 })
51 |
# File 'app/models/landed_cost.rb', line 51 validates :quantity, numericality: { greater_than: 0 } |
Class Method Details
.active ⇒ ActiveRecord::Relation<LandedCost>
A relation of LandedCosts that are active. Active Record Scope
48 |
# File 'app/models/landed_cost.rb', line 48 scope :active, -> { where(state: 'created') } |
.actual ⇒ ActiveRecord::Relation<LandedCost>
A relation of LandedCosts that are actual. Active Record Scope
47 |
# File 'app/models/landed_cost.rb', line 47 scope :actual, -> { where(state: 'created', estimated: false) } |
.estimated ⇒ ActiveRecord::Relation<LandedCost>
A relation of LandedCosts that are estimated. Active Record Scope
46 |
# File 'app/models/landed_cost.rb', line 46 scope :estimated, -> { where(state: 'created', estimated: true) } |
Instance Method Details
#carrier ⇒ Supplier
40 |
# File 'app/models/landed_cost.rb', line 40 belongs_to :carrier, class_name: 'Supplier', optional: true |
#currency_symbol ⇒ Object
190 191 192 |
# File 'app/models/landed_cost.rb', line 190 def currency_symbol Money::Currency.new(currency).symbol end |
#item_ledger_entries ⇒ ActiveRecord::Relation<ItemLedgerEntry>
41 |
# File 'app/models/landed_cost.rb', line 41 has_many :item_ledger_entries |
#ledger_transactions ⇒ ActiveRecord::Relation<LedgerTransaction>
42 |
# File 'app/models/landed_cost.rb', line 42 has_many :ledger_transactions |
#purchase_order ⇒ PurchaseOrder
36 |
# File 'app/models/landed_cost.rb', line 36 belongs_to :purchase_order, optional: true |
#purchase_order_item ⇒ PurchaseOrderItem
37 |
# File 'app/models/landed_cost.rb', line 37 belongs_to :purchase_order_item, optional: true |
#reverse_ledgers ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'app/models/landed_cost.rb', line 67 def reverse_ledgers transaction do receipts_not_vouchered_account = LedgerCompanyAccount.for_company_and_account(purchase_order.company_id, RECEIPTS_NOT_VOUCHERED_ACCOUNT) freight_on_purchasing_account = LedgerCompanyAccount.for_company_and_account(purchase_order.company_id, FREIGHT_ON_PURCHASING_ACCOUNT) business_unit = purchase_order.store.company.default_business_unit goods_account = LedgerCompanyAccount.for_company_and_account(purchase_order.company_id, purchase_order.store.goods_account) services_account = LedgerCompanyAccount.for_company_and_account(purchase_order.company_id, purchase_order.store.services_account) raise 'Unable to find Purchased Finished Goods company account' if goods_account.nil? raise 'Unable to find Services-Pending Fulfillment Debit company account' if services_account.nil? raise 'Unable to find Receipts Not Vouchered company account' if receipts_not_vouchered_account.nil? raise 'Unable to find Freight on Purchasing company account' if freight_on_purchasing_account.nil? raise 'Unable to find default business unit' if business_unit.nil? account_to_use = if purchase_order_item.item.present? and purchase_order_item.item.tax_class == 'svc' services_account else goods_account end existing_ledger_transaction = ledger_transactions.first existing_ledger_entry = existing_ledger_transaction&.ledger_entries&.first # use 2-decimal adjusted total to mirror forward posting and avoid rounding residue total_landed_cost_adjusted = total_landed_cost.round(2) # for all POs need to # + Purchased Finished Goods (1410) # - Receipts Not Vouchered (4120) # or if we don't have the total qty in stock any more # + Freight on Purchasing (6261) # Use the original entry's company_exchange_rate on the transaction so that # the LedgerEntry#set_company_amount callback (which runs after clear_exchange_rates # wipes entry-level rates) picks up the original rate instead of looking up a new # rate for the reversal date. This keeps the ledger entries consistent with the # item ledger entry, which also uses the original rate. original_exchange_rate = existing_ledger_entry&.company_exchange_rate || existing_ledger_transaction.exchange_rate transaction = LedgerTransaction.new(transaction_type: 'PO_LANDED_COST', transaction_date: Date.current, currency: currency, company: purchase_order.company, landed_cost: self, exchange_rate: original_exchange_rate) transaction.ledger_entries << LedgerEntry.new(ledger_company_account_id: receipts_not_vouchered_account.id, currency: currency, amount: total_landed_cost_adjusted, company_exchange_rate: existing_ledger_entry&.company_exchange_rate, consolidated_exchange_rate: existing_ledger_entry&.consolidated_exchange_rate) store_item = StoreItem.where(store_id: purchase_order.store_id, item_id: purchase_order_item.item_id, location: 'AVAILABLE').first existing_item_ledger_entry = item_ledger_entries.first qty_originally_applied = existing_item_ledger_entry.nil? ? 0 : existing_item_ledger_entry.quantity_eval qty_to_gl = quantity - qty_originally_applied qty_to_apply = qty_originally_applied qty_currently_in_stock = store_item.qty_on_hand running_total = total_landed_cost_adjusted if qty_to_gl > 0 # the amount we originally added to the g/l needs to go back to the g/l if qty_to_gl == quantity amount = total_landed_cost_adjusted else calculated_amount = (qty_to_gl * unit_landed_cost).round(2) amount = calculated_amount > running_total ? running_total : calculated_amount end transaction.ledger_entries << LedgerEntry.new(ledger_company_account_id: freight_on_purchasing_account.id, currency: currency, amount: -amount, business_unit_id: business_unit.id, company_exchange_rate: existing_ledger_entry&.company_exchange_rate, consolidated_exchange_rate: existing_ledger_entry&.consolidated_exchange_rate) running_total -= amount end # need to check we have the number of items we originally processed in stock still if qty_to_apply > qty_currently_in_stock remainder = qty_to_apply - qty_currently_in_stock qty_to_apply = qty_currently_in_stock if remainder > 0 # we don't have it all in stock, so remainder needs to be added to the g/l too calculated_amount = (remainder * unit_landed_cost).round(2) amount = calculated_amount > running_total ? running_total : calculated_amount transaction.ledger_entries << LedgerEntry.new(ledger_company_account_id: freight_on_purchasing_account.id, currency: currency, amount: -amount, business_unit_id: business_unit.id, company_exchange_rate: existing_ledger_entry&.company_exchange_rate, consolidated_exchange_rate: existing_ledger_entry&.consolidated_exchange_rate) running_total -= amount end end if qty_to_apply > 0 transaction.ledger_entries << LedgerEntry.new(ledger_company_account_id: account_to_use.id, currency: currency, amount: -running_total, company_exchange_rate: existing_ledger_entry&.company_exchange_rate, consolidated_exchange_rate: existing_ledger_entry&.consolidated_exchange_rate) elsif running_total != 0 # No inventory re-application: ensure we zero out any rounding residue by balancing to Freight on Purchasing transaction.ledger_entries << LedgerEntry.new(ledger_company_account_id: freight_on_purchasing_account.id, currency: currency, amount: -running_total, business_unit_id: business_unit.id, company_exchange_rate: existing_ledger_entry&.company_exchange_rate, consolidated_exchange_rate: existing_ledger_entry&.consolidated_exchange_rate) end transaction.save! if currency == purchase_order.company.currency currency_to_use = currency unit_cost_to_use = unit_landed_cost total_cost_to_use = unit_landed_cost * -qty_to_apply else # currencies don't match so we need to convert to company currency, use original exchange rate rate = existing_ledger_entry&.company_exchange_rate currency_to_use = purchase_order.company.currency unit_cost_to_use = unit_landed_cost * rate total_cost_to_use = (unit_landed_cost * -qty_to_apply) * rate end # when a landed cost is voided we need to reverse the item ledger entry ItemLedgerEntry.create!(category: 'PO_LANDED_COST', store: purchase_order.store, item: purchase_order_item.item, gl_date: Date.current, quantity: 0, quantity_eval: -qty_to_apply, currency: currency_to_use, unit_cost: unit_cost_to_use, total_cost: total_cost_to_use, landed_cost: self, location: shipment_receipt.location, ledger_transaction: transaction) end end |
#shipment_receipt ⇒ ShipmentReceipt
39 |
# File 'app/models/landed_cost.rb', line 39 belongs_to :shipment_receipt, optional: true |
#shipment_receipt_item ⇒ ShipmentReceiptItem
38 |
# File 'app/models/landed_cost.rb', line 38 belongs_to :shipment_receipt_item, optional: true |