bscf-core 0.3.99 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ba4cb08d046b4bcef3b55100146f08c64fa32d7b97f59302ffdf8ef1a804737
4
- data.tar.gz: da7bd6abdf23ec993e8442e998853118533d2f2d7773de25155aca33c6569c22
3
+ metadata.gz: edbe11919e64a7d36377d85759973899a2407eb6417e7d070eb78ee9c2062bf6
4
+ data.tar.gz: 37375af1d5dfdf4f4703540d8e3c6d7c2d7496026421b8ae8e4c5c412cb23fd2
5
5
  SHA512:
6
- metadata.gz: 7eca0f066d06df32ff1fcbf12c1056331ada9eef7f5f5cd18d37becc26dfad27a3576e9afc97e157bd7bd133a5c28534c70aeb2c74592c325b67b51bcf42f6e4
7
- data.tar.gz: 35654a8b5fab7cb7b4bfdaa124014cbf80e9c1b640079ec43a2d95800672d34db54e7ee89c3cacf31eff19f6b627b7e56f8a5f335d70a9308939a19b4932b0b3
6
+ metadata.gz: 2de3ef4fe24d2536031b4f527a5d7ed90f958f736d255157a9e17836c50e8587d00fa06ed2128e14b35102af7b81a9ba74bcc6994047f755e728e9e6cf1d1b9c
7
+ data.tar.gz: 80a64d9c90c60baaf9966dee56261e41675a9fcf8e3091059b994e8fa2af36bc607caf192a22504fa74cff29b7d7fca4bc8e6061918c0db991e3556f739c590b
@@ -9,8 +9,7 @@ module Bscf::Core
9
9
  has_many :order_items, through: :delivery_order_items
10
10
  has_many :products, through: :delivery_order_items
11
11
 
12
- validates :buyer_phone, :seller_phone, :driver_phone,
13
- :status, :estimated_delivery_time, presence: true
12
+ validates :driver_phone, :status, :estimated_delivery_time, presence: true
14
13
  validate :end_time_after_start_time, if: -> { delivery_start_time.present? && delivery_end_time.present? }
15
14
 
16
15
  before_save :update_delivery_times
@@ -2,7 +2,8 @@ module Bscf::Core
2
2
  class DeliveryOrderItem < ApplicationRecord
3
3
  belongs_to :delivery_order
4
4
  belongs_to :order_item
5
- belongs_to :product
5
+ belongs_to :pickup_address, class_name: "Bscf::Core::Address", optional: true
6
+ belongs_to :dropoff_address, class_name: "Bscf::Core::Address", optional: true
6
7
 
7
8
  validates :quantity, :status, presence: true
8
9
  validate :quantity_not_exceeding_order_item
@@ -1,20 +1,27 @@
1
1
  module Bscf
2
2
  module Core
3
3
  class VirtualAccountTransaction < ApplicationRecord
4
- belongs_to :from_account, class_name: "Bscf::Core::VirtualAccount", optional: true
5
- belongs_to :to_account, class_name: "Bscf::Core::VirtualAccount", optional: true
4
+ belongs_to :account, class_name: "Bscf::Core::VirtualAccount"
5
+ belongs_to :paired_transaction, class_name: "Bscf::Core::VirtualAccountTransaction", optional: true
6
6
 
7
- validates :from_account_id, presence: true, if: :requires_from_account?
8
- validates :to_account_id, presence: true, if: :requires_to_account?
7
+ validates :account_id, presence: true
9
8
  validates :amount, presence: true, numericality: { greater_than: 0 }
10
9
  validates :transaction_type, presence: true
10
+ validates :entry_type, presence: true
11
11
  validates :status, presence: true
12
12
  validates :reference_number, presence: true, uniqueness: true
13
13
 
14
14
  enum :transaction_type, {
15
15
  transfer: 0,
16
16
  deposit: 1,
17
- withdrawal: 2
17
+ withdrawal: 2,
18
+ fee: 3,
19
+ adjustment: 4
20
+ }
21
+
22
+ enum :entry_type, {
23
+ debit: 0,
24
+ credit: 1
18
25
  }
19
26
 
20
27
  enum :status, {
@@ -27,122 +34,76 @@ module Bscf
27
34
  before_validation :generate_reference_number, on: :create
28
35
  validate :validate_transaction, on: :create
29
36
 
37
+ scope :debits, -> { where(entry_type: :debit) }
38
+ scope :credits, -> { where(entry_type: :credit) }
39
+ scope :for_account, ->(account_id) { where(account_id: account_id) }
40
+ scope :by_type, ->(type) { where(transaction_type: type) }
41
+ scope :by_status, ->(status) { where(status: status) }
42
+
30
43
  def process!
31
44
  return false unless pending?
32
45
 
33
46
  ActiveRecord::Base.transaction do
34
- process_transaction
47
+ update_account_balance
48
+
35
49
  update!(status: :completed)
50
+ paired_transaction&.update!(status: :completed)
36
51
  end
37
52
  true
38
53
  rescue StandardError => e
39
54
  update(status: :failed)
55
+ paired_transaction&.update(status: :failed)
56
+ Rails.logger.error("Transaction processing failed: #{e.message}")
40
57
  false
41
58
  end
42
59
 
43
60
  def cancel!
44
61
  return false unless pending?
45
- update(status: :cancelled)
46
- end
47
-
48
- private
49
-
50
- def requires_from_account?
51
- return false if transaction_type.nil?
52
- %w[transfer withdrawal].include?(transaction_type)
53
- end
54
62
 
55
- def requires_to_account?
56
- return false if transaction_type.nil?
57
- %w[transfer deposit].include?(transaction_type)
58
- end
59
-
60
- def validate_transaction
61
- case transaction_type.to_sym
62
- when :transfer
63
- validate_transfer
64
- when :withdrawal
65
- validate_withdrawal
66
- when :deposit
67
- validate_deposit
63
+ ActiveRecord::Base.transaction do
64
+ update(status: :cancelled)
65
+ paired_transaction&.update(status: :cancelled)
68
66
  end
69
-
70
- validate_account_requirements
71
- end
72
-
73
- def validate_transfer
74
- return unless from_account && to_account
75
-
76
- errors.add(:from_account, "must be active") unless from_account.active?
77
- errors.add(:to_account, "must be active") unless to_account.active?
78
- errors.add(:from_account, "insufficient balance") if from_account.balance.to_d < amount.to_d
67
+ true
79
68
  end
80
69
 
81
70
  private
82
71
 
83
- def validate_account_requirements
84
- case transaction_type.to_sym
85
- when :transfer
86
- return if from_account_id.present? && to_account_id.present?
87
- errors.add(:base, "Both accounts are required for transfer")
88
- when :withdrawal
89
- return if from_account_id.present?
90
- errors.add(:base, "Source account is required for withdrawal")
91
- errors.add(:to_account_id, "must be blank for withdrawal")
92
- when :deposit
93
- return if to_account_id.present?
94
- errors.add(:base, "Destination account is required for deposit")
95
- errors.add(:from_account_id, "must be blank for deposit")
96
- end
97
- end
98
-
99
- def validate_withdrawal
100
- return unless from_account
101
- errors.add(:from_account, "must be active") unless from_account.active?
102
- errors.add(:from_account, "insufficient balance") if from_account.balance.to_d < amount.to_d
103
- end
72
+ def validate_transaction
73
+ errors.add(:account, "must be active") unless account.active?
104
74
 
105
- def validate_deposit
106
- return unless to_account
107
- errors.add(:to_account, "must be active") unless to_account.active?
108
- end
75
+ if debit? && !adjustment? && account.balance.to_d < amount.to_d
76
+ errors.add(:account, "insufficient balance")
77
+ end
109
78
 
110
- def process_transaction
111
- case transaction_type.to_sym
112
- when :transfer
113
- process_transfer
114
- when :withdrawal
115
- process_withdrawal
116
- when :deposit
117
- process_deposit
79
+ if transfer? && paired_transaction.blank?
80
+ errors.add(:paired_transaction, "must be present for transfers")
118
81
  end
119
82
  end
120
83
 
121
- def process_transfer
122
- ActiveRecord::Base.transaction do
123
- from_account.with_lock do
124
- to_account.with_lock do
125
- new_from_balance = (from_account.balance - amount).round(2)
126
- new_to_balance = (to_account.balance + amount).round(2)
127
-
128
- from_account.update!(balance: new_from_balance)
129
- to_account.update!(balance: new_to_balance)
130
- end
84
+ def update_account_balance
85
+ account.with_lock do
86
+ new_balance = if debit?
87
+ (account.balance - amount).round(2)
88
+ else
89
+ (account.balance + amount).round(2)
131
90
  end
132
- end
133
- end
134
91
 
135
- def process_withdrawal
136
- from_account.with_lock do
137
- new_balance = (from_account.balance - amount).round(2)
138
- from_account.update!(balance: new_balance)
92
+ account.update!(balance: new_balance)
93
+ update!(running_balance: new_balance)
139
94
  end
140
- end
141
95
 
142
- def process_deposit
143
- to_account.with_lock do
144
- new_balance = (to_account.balance + amount).round(2)
145
- to_account.update!(balance: new_balance)
96
+ if paired_transaction.present?
97
+ paired_transaction.account.with_lock do
98
+ new_balance = if paired_transaction.debit?
99
+ (paired_transaction.account.balance - paired_transaction.amount).round(2)
100
+ else
101
+ (paired_transaction.account.balance + paired_transaction.amount).round(2)
102
+ end
103
+
104
+ paired_transaction.account.update!(balance: new_balance)
105
+ paired_transaction.update!(running_balance: new_balance)
106
+ end
146
107
  end
147
108
  end
148
109
 
@@ -0,0 +1,185 @@
1
+ module Bscf
2
+ module Core
3
+ class TransactionService
4
+ # Create a transfer between two accounts
5
+ # @param from_account_id [Integer] Source account ID
6
+ # @param to_account_id [Integer] Destination account ID
7
+ # @param amount [Decimal] Amount to transfer
8
+ # @param description [String] Optional description
9
+ # @return [Array<VirtualAccountTransaction>] The created transaction pair
10
+ def self.create_transfer(from_account_id:, to_account_id:, amount:, description: nil)
11
+ create_paired_transaction(
12
+ from_account_id: from_account_id,
13
+ to_account_id: to_account_id,
14
+ amount: amount,
15
+ transaction_type: :transfer,
16
+ description: description
17
+ )
18
+ end
19
+
20
+ # Create a deposit to an account
21
+ # @param to_account_id [Integer] Destination account ID
22
+ # @param amount [Decimal] Amount to deposit
23
+ # @param description [String] Optional description
24
+ # @return [Array<VirtualAccountTransaction>] The created transaction pair
25
+ def self.create_deposit(to_account_id:, amount:, description: nil)
26
+ system_account = find_or_create_system_account("DEPOSIT_ACCOUNT")
27
+
28
+ # Ensure system account has sufficient balance for deposits
29
+ ensure_system_account_balance(system_account, amount)
30
+
31
+ create_paired_transaction(
32
+ from_account_id: system_account.id,
33
+ to_account_id: to_account_id,
34
+ amount: amount,
35
+ transaction_type: :deposit,
36
+ description: description
37
+ )
38
+ end
39
+
40
+ # Create a withdrawal from an account
41
+ # @param from_account_id [Integer] Source account ID
42
+ # @param amount [Decimal] Amount to withdraw
43
+ # @param description [String] Optional description
44
+ # @return [Array<VirtualAccountTransaction>] The created transaction pair
45
+ def self.create_withdrawal(from_account_id:, amount:, description: nil)
46
+ system_account = find_or_create_system_account("WITHDRAWAL_ACCOUNT")
47
+
48
+ create_paired_transaction(
49
+ from_account_id: from_account_id,
50
+ to_account_id: system_account.id,
51
+ amount: amount,
52
+ transaction_type: :withdrawal,
53
+ description: description
54
+ )
55
+ end
56
+
57
+ # Create a fee transaction
58
+ # @param from_account_id [Integer] Account to charge
59
+ # @param amount [Decimal] Fee amount
60
+ # @param description [String] Optional description
61
+ # @return [Array<VirtualAccountTransaction>] The created transaction pair
62
+ def self.create_fee(from_account_id:, amount:, description: nil)
63
+ fee_account = find_or_create_system_account("FEE_ACCOUNT")
64
+
65
+ create_paired_transaction(
66
+ from_account_id: from_account_id,
67
+ to_account_id: fee_account.id,
68
+ amount: amount,
69
+ transaction_type: :fee,
70
+ description: description
71
+ )
72
+ end
73
+
74
+ # Create an adjustment to an account
75
+ # @param account_id [Integer] Account to adjust
76
+ # @param amount [Decimal] Adjustment amount
77
+ # @param is_debit [Boolean] Whether this is a debit (true) or credit (false)
78
+ # @param description [String] Optional description
79
+ # @return [VirtualAccountTransaction] The created adjustment transaction
80
+ def self.create_adjustment(account_id:, amount:, is_debit: true, description: nil)
81
+ reference_number = generate_reference_number
82
+
83
+ VirtualAccountTransaction.create!(
84
+ transaction_type: :adjustment,
85
+ entry_type: is_debit ? :debit : :credit,
86
+ account_id: account_id,
87
+ amount: amount,
88
+ reference_number: reference_number,
89
+ description: description,
90
+ status: :pending
91
+ )
92
+ end
93
+
94
+ # Process a transaction
95
+ # @param transaction [VirtualAccountTransaction] Transaction to process
96
+ # @return [Boolean] Success or failure
97
+ def self.process(transaction)
98
+ transaction.process!
99
+ end
100
+
101
+ # Cancel a transaction
102
+ # @param transaction [VirtualAccountTransaction] Transaction to cancel
103
+ # @return [Boolean] Success or failure
104
+ def self.cancel(transaction)
105
+ transaction.cancel!
106
+ end
107
+
108
+ private
109
+
110
+ def self.create_paired_transaction(from_account_id:, to_account_id:, amount:, transaction_type:, description: nil)
111
+ reference_number = generate_reference_number
112
+
113
+ ActiveRecord::Base.transaction do
114
+ # Debit entry (from account)
115
+ debit = VirtualAccountTransaction.create!(
116
+ transaction_type: transaction_type,
117
+ entry_type: :debit,
118
+ account_id: from_account_id,
119
+ amount: amount,
120
+ reference_number: reference_number,
121
+ description: description,
122
+ status: :pending
123
+ )
124
+
125
+ # Credit entry (to account)
126
+ credit = VirtualAccountTransaction.create!(
127
+ transaction_type: transaction_type,
128
+ entry_type: :credit,
129
+ account_id: to_account_id,
130
+ amount: amount,
131
+ reference_number: reference_number,
132
+ description: description,
133
+ status: :pending,
134
+ paired_transaction_id: debit.id
135
+ )
136
+
137
+ # Update the paired_transaction_id for the debit entry
138
+ debit.update!(paired_transaction_id: credit.id)
139
+
140
+ [ debit, credit ]
141
+ end
142
+ end
143
+
144
+ def self.find_or_create_system_account(account_identifier)
145
+ # Find or create a system account for external transactions
146
+ account = VirtualAccount.find_or_create_by!(account_number: account_identifier) do |account|
147
+ # Set default values for a new system account
148
+ account.user_id = find_or_create_system_user.id
149
+ account.cbs_account_number = account_identifier
150
+ account.branch_code = "SYSTEM"
151
+ account.product_scheme = "SAVINGS"
152
+ account.voucher_type = "REGULAR"
153
+ account.interest_rate = 0
154
+ account.interest_type = :simple
155
+ account.balance = 100000.00 # Initialize with a large balance
156
+ account.locked_amount = 0
157
+ account.status = :active
158
+ end
159
+
160
+ account
161
+ end
162
+
163
+ def self.ensure_system_account_balance(account, required_amount)
164
+ # Top up the system account if needed
165
+ if account.balance < required_amount
166
+ account.update!(balance: account.balance + required_amount * 2)
167
+ end
168
+ end
169
+
170
+ def self.find_or_create_system_user
171
+ User.find_or_create_by!(phone_number: "SYSTEM_USER") do |user|
172
+ user.first_name = "System"
173
+ user.last_name = "User"
174
+ user.password = SecureRandom.hex(8)
175
+ end
176
+ end
177
+
178
+ def self.generate_reference_number
179
+ timestamp = Time.current.strftime("%Y%m%d%H%M%S")
180
+ random = SecureRandom.hex(3)
181
+ "TXN#{timestamp}#{random}"
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,20 @@
1
+ class AddAccountingFieldsToVirtualAccountTransactions < ActiveRecord::Migration[8.0]
2
+ def change
3
+ # Add new accounting fields
4
+ add_column :bscf_core_virtual_account_transactions, :entry_type, :integer
5
+ add_reference :bscf_core_virtual_account_transactions, :account, null: false, foreign_key: { to_table: :bscf_core_virtual_accounts }
6
+ add_column :bscf_core_virtual_account_transactions, :running_balance, :decimal, precision: 10, scale: 2
7
+ add_reference :bscf_core_virtual_account_transactions, :paired_transaction, null: true, foreign_key: { to_table: :bscf_core_virtual_account_transactions }
8
+ add_column :bscf_core_virtual_account_transactions, :value_date, :datetime
9
+
10
+ # Add new indexes
11
+ add_index :bscf_core_virtual_account_transactions, [ :account_id, :reference_number ]
12
+ add_index :bscf_core_virtual_account_transactions, :entry_type
13
+
14
+ # Remove old fields and indexes
15
+ remove_index :bscf_core_virtual_account_transactions, [ :from_account_id, :reference_number ], if_exists: true
16
+ remove_index :bscf_core_virtual_account_transactions, [ :to_account_id, :reference_number ], if_exists: true
17
+ remove_reference :bscf_core_virtual_account_transactions, :from_account
18
+ remove_reference :bscf_core_virtual_account_transactions, :to_account
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ class UpdateDeliveryTables < ActiveRecord::Migration[8.0]
2
+ def up
3
+ remove_column :bscf_core_delivery_orders, :buyer_phone
4
+ remove_column :bscf_core_delivery_orders, :seller_phone
5
+
6
+ add_column :bscf_core_delivery_orders, :estimated_delivery_price, :float
7
+
8
+ rename_column :bscf_core_delivery_orders, :delivery_price, :actual_delivery_price
9
+
10
+ add_reference :bscf_core_delivery_order_items, :pickup_address, foreign_key: { to_table: :bscf_core_addresses }
11
+ add_reference :bscf_core_delivery_order_items, :dropoff_address, foreign_key: { to_table: :bscf_core_addresses }
12
+
13
+ remove_reference :bscf_core_delivery_order_items, :product
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  module Bscf
2
2
  module Core
3
- VERSION = "0.3.99"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
@@ -2,7 +2,8 @@ FactoryBot.define do
2
2
  factory :delivery_order_item, class: 'Bscf::Core::DeliveryOrderItem' do
3
3
  association :delivery_order
4
4
  association :order_item
5
- association :product
5
+ association :pickup_address, factory: :address
6
+ association :dropoff_address, factory: :address
6
7
  quantity { order_item.quantity }
7
8
  status { :pending }
8
9
  notes { Faker::Lorem.paragraph }
@@ -2,38 +2,15 @@ FactoryBot.define do
2
2
  factory :delivery_order, class: 'Bscf::Core::DeliveryOrder' do
3
3
  association :pickup_address, factory: :address
4
4
  association :dropoff_address, factory: :address
5
- driver { nil }
5
+ association :driver, factory: :user
6
6
 
7
- buyer_phone { Faker::PhoneNumber.phone_number }
8
- seller_phone { Faker::PhoneNumber.phone_number }
9
7
  driver_phone { Faker::PhoneNumber.phone_number }
10
8
  delivery_notes { Faker::Lorem.paragraph }
11
9
  estimated_delivery_time { 2.days.from_now }
10
+ estimated_delivery_price { Faker::Number.decimal(l_digits: 2, r_digits: 2) }
11
+ actual_delivery_price { Faker::Number.decimal(l_digits: 2, r_digits: 2) }
12
12
  delivery_start_time { nil }
13
13
  delivery_end_time { nil }
14
14
  status { :pending }
15
-
16
- trait :with_driver do
17
- association :driver, factory: :user
18
- end
19
-
20
- trait :in_transit do
21
- with_driver
22
- status { :in_transit }
23
- delivery_start_time { Time.current }
24
- end
25
-
26
- trait :delivered do
27
- with_driver
28
- status { :delivered }
29
- delivery_start_time { 2.hours.ago }
30
- delivery_end_time { Time.current }
31
- end
32
-
33
- trait :with_orders do
34
- after(:create) do |delivery_order|
35
- create_list(:order, 2, delivery_order: delivery_order)
36
- end
37
- end
38
15
  end
39
16
  end
@@ -1,34 +1,49 @@
1
1
  FactoryBot.define do
2
2
  factory :virtual_account_transaction, class: 'Bscf::Core::VirtualAccountTransaction' do
3
- association :from_account, factory: :virtual_account, status: :active, balance: 10000
4
- association :to_account, factory: :virtual_account, status: :active, balance: 5000
3
+ association :account, factory: :virtual_account, status: :active, balance: 10000
5
4
  amount { 100.0 }
6
- transaction_type { :transfer }
5
+ transaction_type { :adjustment }
6
+ entry_type { :debit }
7
7
  status { :pending }
8
+ value_date { Time.current }
8
9
  description { Faker::Lorem.sentence }
10
+ running_balance { nil }
9
11
 
10
- trait :completed do
11
- status { :completed }
12
- end
13
-
14
- trait :failed do
15
- status { :failed }
16
- end
12
+ factory :paired_transaction do
13
+ transient do
14
+ paired_account { create(:virtual_account, status: :active, balance: 10000) }
15
+ is_credit { false }
16
+ end
17
17
 
18
- trait :cancelled do
19
- status { :cancelled }
20
- end
18
+ after(:build) do |transaction, evaluator|
19
+ if transaction.transaction_type == 'transfer'
20
+ paired_entry_type = transaction.entry_type == 'debit' ? :credit : :debit
21
+ elsif transaction.transaction_type == 'deposit'
22
+ paired_entry_type = transaction.entry_type == 'debit' ? :credit : :debit
23
+ elsif transaction.transaction_type == 'withdrawal'
24
+ paired_entry_type = transaction.entry_type == 'debit' ? :credit : :debit
25
+ else
26
+ paired_entry_type = evaluator.is_credit ? :credit : :debit
27
+ end
21
28
 
22
- trait :deposit do
23
- transaction_type { :deposit }
24
- end
29
+ paired = build(:virtual_account_transaction,
30
+ transaction_type: transaction.transaction_type,
31
+ entry_type: paired_entry_type,
32
+ account: evaluator.paired_account,
33
+ amount: transaction.amount,
34
+ reference_number: transaction.reference_number,
35
+ value_date: transaction.value_date,
36
+ status: transaction.status
37
+ )
25
38
 
26
- trait :withdrawal do
27
- transaction_type { :withdrawal }
28
- end
39
+ transaction.paired_transaction = paired
40
+ paired.paired_transaction = transaction
41
+ end
29
42
 
30
- trait :with_large_amount do
31
- amount { 5000.0 }
43
+ after(:create) do |transaction, evaluator|
44
+ # Save the paired transaction after the main transaction is created
45
+ transaction.paired_transaction.save! if transaction.paired_transaction&.new_record?
46
+ end
32
47
  end
33
48
  end
34
49
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bscf-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.99
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asrat
@@ -311,6 +311,7 @@ files:
311
311
  - app/models/bscf/core/voucher.rb
312
312
  - app/models/bscf/core/wholesaler_product.rb
313
313
  - app/services/bscf/core/token_service.rb
314
+ - app/services/bscf/core/transaction_service.rb
314
315
  - config/database.yml
315
316
  - config/routes.rb
316
317
  - db/migrate/20250326065606_create_bscf_core_users.rb
@@ -345,6 +346,8 @@ files:
345
346
  - db/migrate/20250524081221_create_bscf_core_vouchers.rb
346
347
  - db/migrate/20250524151346_add_locked_amount_to_virtual_accounts.rb
347
348
  - db/migrate/20250606100158_add_product_to_market_place_listings.rb
349
+ - db/migrate/20250609180530_add_accounting_fields_to_virtual_account_transactions.rb
350
+ - db/migrate/20250610120351_update_delivery_tables.rb
348
351
  - lib/bscf/core.rb
349
352
  - lib/bscf/core/engine.rb
350
353
  - lib/bscf/core/version.rb