bscf-core 0.1.0 → 0.2.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 +4 -4
- data/Rakefile +1 -1
- data/app/models/bscf/core/address.rb +7 -0
- data/app/models/bscf/core/business.rb +15 -0
- data/app/models/bscf/core/category.rb +11 -0
- data/app/models/bscf/core/order.rb +24 -0
- data/app/models/bscf/core/order_item.rb +15 -0
- data/app/models/bscf/core/product.rb +29 -0
- data/app/models/bscf/core/quotation.rb +29 -0
- data/app/models/bscf/core/quotation_item.rb +23 -0
- data/app/models/bscf/core/request_for_quotation.rb +13 -0
- data/app/models/bscf/core/rfq_item.rb +9 -0
- data/app/models/bscf/core/role.rb +10 -0
- data/app/models/bscf/core/user.rb +21 -0
- data/app/models/bscf/core/user_profile.rb +26 -0
- data/app/models/bscf/core/user_role.rb +8 -0
- data/app/models/bscf/core/virtual_account.rb +53 -0
- data/app/models/bscf/core/virtual_account_transaction.rb +158 -0
- data/db/migrate/20250326065606_create_bscf_core_users.rb +18 -0
- data/db/migrate/20250326075111_create_bscf_core_roles.rb +9 -0
- data/db/migrate/20250326080646_create_bscf_core_user_profiles.rb +19 -0
- data/db/migrate/20250326081052_create_bscf_core_addresses.rb +14 -0
- data/db/migrate/20250326084233_create_bscf_core_user_roles.rb +10 -0
- data/db/migrate/20250326085741_create_bscf_core_virtual_accounts.rb +24 -0
- data/db/migrate/20250326103305_create_bscf_core_categories.rb +11 -0
- data/db/migrate/20250326105652_create_bscf_core_products.rb +14 -0
- data/db/migrate/20250326112449_create_bscf_core_businesses.rb +14 -0
- data/db/migrate/20250326115203_create_bscf_core_request_for_quotations.rb +11 -0
- data/db/migrate/20250326120613_create_bscf_core_rfq_items.rb +12 -0
- data/db/migrate/20250326121246_create_bscf_core_bscf_core_virtual_account_transactions.rb +19 -0
- data/db/migrate/20250327041651_create_bscf_core_quotations.rb +15 -0
- data/db/migrate/20250327044020_create_bscf_core_quotation_items.rb +15 -0
- data/db/migrate/20250327102217_create_bscf_core_orders.rb +14 -0
- data/db/migrate/20250327112412_create_bscf_core_order_items.rb +14 -0
- data/lib/bscf/core/engine.rb +18 -0
- data/lib/bscf/core/version.rb +1 -1
- data/lib/tasks/release.rake +42 -0
- data/spec/dummy/db/schema.rb +246 -0
- data/spec/dummy/log/development.log +2060 -0
- data/spec/dummy/log/test.log +69259 -0
- data/spec/examples.txt +167 -3
- data/spec/factories/bscf/core/addresses.rb +10 -0
- data/spec/factories/bscf/core/businesses.rb +24 -0
- data/spec/factories/bscf/core/categories.rb +16 -0
- data/spec/factories/bscf/core/order_items.rb +10 -0
- data/spec/factories/bscf/core/orders.rb +10 -0
- data/spec/factories/bscf/core/products.rb +8 -0
- data/spec/factories/bscf/core/quotation_items.rb +11 -0
- data/spec/factories/bscf/core/quotations.rb +28 -0
- data/spec/factories/bscf/core/request_for_quotations.rb +7 -0
- data/spec/factories/bscf/core/rfq_items.rb +8 -0
- data/spec/factories/bscf/core/roles.rb +5 -0
- data/spec/factories/bscf/core/user_profiles.rb +15 -0
- data/spec/factories/bscf/core/user_roles.rb +6 -0
- data/spec/factories/bscf/core/users.rb +10 -0
- data/spec/factories/bscf/core/virtual_account_transactions.rb +34 -0
- data/spec/factories/bscf/core/virtual_accounts.rb +38 -0
- data/spec/models/bscf/core/address_spec.rb +12 -0
- data/spec/models/bscf/core/business_spec.rb +64 -0
- data/spec/models/bscf/core/category_spec.rb +43 -0
- data/spec/models/bscf/core/order_item_spec.rb +26 -0
- data/spec/models/bscf/core/order_spec.rb +16 -0
- data/spec/models/bscf/core/product_spec.rb +47 -0
- data/spec/models/bscf/core/quotation_item_spec.rb +44 -0
- data/spec/models/bscf/core/quotation_spec.rb +41 -0
- data/spec/models/bscf/core/request_for_quotation_spec.rb +13 -0
- data/spec/models/bscf/core/rfq_item_spec.rb +14 -0
- data/spec/models/bscf/core/role_spec.rb +14 -0
- data/spec/models/bscf/core/user_profile_spec.rb +20 -0
- data/spec/models/bscf/core/user_role_spec.rb +13 -0
- data/spec/models/bscf/core/user_spec.rb +22 -0
- data/spec/models/bscf/core/virtual_account_spec.rb +111 -0
- data/spec/models/bscf/core/virtual_account_transaction_spec.rb +133 -0
- data/spec/spec_helper.rb +4 -1
- data/spec/support/requests/shared_requests.rb +4 -4
- metadata +69 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b265836a53a2c3d1b4c492d064732a6203150366915f479897ee293690414d3
|
4
|
+
data.tar.gz: 444ed29066f85fb8b2d0defd0c3c798bac8a657ef09ba6e1d6777204edff7a1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e5cd8ca766f662abc09b4d1962b252087323fa2439773f4afdb3cde3dcf03fe0794ee860a130c3c48acdb44215a1ace729a38041bcae5ff38f16a55d57aee75
|
7
|
+
data.tar.gz: 8ea894bd332364d89656120224bdd57ec808dc80e6c588ff9be84b40fb030f7d449e80dc0bd6622064fe647eb71e31eef3d5a9de9a483507bc6db6983516b631
|
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@ require "bundler/setup"
|
|
2
2
|
|
3
3
|
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
4
4
|
load "rails/tasks/engine.rake"
|
5
|
-
|
6
5
|
load "rails/tasks/statistics.rake"
|
7
6
|
|
8
7
|
require "bundler/gem_tasks"
|
8
|
+
Dir[File.join(File.dirname(__FILE__), 'lib/tasks/**/*.rake')].each { |f| load f }
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Bscf
|
2
|
+
module Core
|
3
|
+
class Business < ApplicationRecord
|
4
|
+
belongs_to :user
|
5
|
+
|
6
|
+
validates :business_name, presence: true
|
7
|
+
validates :tin_number, presence: true, uniqueness: { case_sensitive: false }
|
8
|
+
validates :business_type, presence: true
|
9
|
+
validates :verification_status, presence: true
|
10
|
+
|
11
|
+
enum :business_type, { retailer: 0, wholesaler: 1 }
|
12
|
+
enum :verification_status, { pending: 0, approved: 1, rejected: 2 }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Bscf
|
2
|
+
module Core
|
3
|
+
class Category < ApplicationRecord
|
4
|
+
validates :name, presence: true
|
5
|
+
validates :description, presence: true
|
6
|
+
|
7
|
+
belongs_to :parent, class_name: "Bscf::Core::Category", optional: true
|
8
|
+
has_many :children, class_name: "Bscf::Core::Category", foreign_key: "parent_id"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Bscf
|
2
|
+
module Core
|
3
|
+
class Order < ApplicationRecord
|
4
|
+
belongs_to :ordered_by, class_name: "Bscf::Core::User", optional: true
|
5
|
+
belongs_to :ordered_to, class_name: "Bscf::Core::User", optional: true
|
6
|
+
belongs_to :quotation, optional: true
|
7
|
+
|
8
|
+
validates :order_type, :status, presence: true
|
9
|
+
|
10
|
+
enum :order_type, {
|
11
|
+
order_from_quote: 0,
|
12
|
+
direct_order: 1
|
13
|
+
}
|
14
|
+
|
15
|
+
enum :status, {
|
16
|
+
draft: 0,
|
17
|
+
submitted: 1,
|
18
|
+
accepted: 3,
|
19
|
+
delivering: 4,
|
20
|
+
canceled: 5
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Bscf::Core
|
2
|
+
class OrderItem < ApplicationRecord
|
3
|
+
belongs_to :order
|
4
|
+
belongs_to :product
|
5
|
+
belongs_to :quotation_item, optional: true
|
6
|
+
before_save :calculate_subtotal
|
7
|
+
|
8
|
+
|
9
|
+
validates :quantity, :unit_price, :subtotal, presence: true
|
10
|
+
|
11
|
+
def calculate_subtotal
|
12
|
+
self.subtotal = (unit_price * quantity).round(2)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Bscf
|
2
|
+
module Core
|
3
|
+
class Product < ApplicationRecord
|
4
|
+
belongs_to :category
|
5
|
+
|
6
|
+
has_many :rfq_items
|
7
|
+
has_many :request_for_quotations, through: :rfq_items
|
8
|
+
|
9
|
+
before_validation :generate_sku, on: :create
|
10
|
+
|
11
|
+
validates :sku, presence: true, uniqueness: true
|
12
|
+
validates :name, presence: true
|
13
|
+
validates :description, presence: true
|
14
|
+
validates :base_price, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def generate_sku
|
19
|
+
return if sku.present?
|
20
|
+
|
21
|
+
prefix = "BSC"
|
22
|
+
category_code = category.id.to_s.rjust(3, "0")
|
23
|
+
sequence = (Product.where("sku LIKE ?", "#{prefix}#{category_code}%").count + 1).to_s.rjust(4, "0")
|
24
|
+
|
25
|
+
self.sku = "#{prefix}#{category_code}#{sequence}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Bscf
|
2
|
+
module Core
|
3
|
+
class Quotation < ApplicationRecord
|
4
|
+
belongs_to :request_for_quotation
|
5
|
+
belongs_to :business
|
6
|
+
|
7
|
+
has_many :quotation_items
|
8
|
+
has_many :products, through: :quotation_items
|
9
|
+
has_many :orders
|
10
|
+
|
11
|
+
validates :price, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
12
|
+
validates :delivery_date, presence: true
|
13
|
+
validates :valid_until, presence: true
|
14
|
+
validates :status, presence: true
|
15
|
+
|
16
|
+
enum :status, {
|
17
|
+
draft: 0,
|
18
|
+
submitted: 1,
|
19
|
+
accepted: 2,
|
20
|
+
rejected: 3,
|
21
|
+
expired: 4
|
22
|
+
}
|
23
|
+
|
24
|
+
scope :active, -> { where.not(status: [ :rejected, :expired ]) }
|
25
|
+
scope :by_business, ->(business_id) { where(business_id: business_id) }
|
26
|
+
scope :by_rfq, ->(rfq_id) { where(request_for_quotation_id: rfq_id) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Bscf
|
2
|
+
module Core
|
3
|
+
class QuotationItem < ApplicationRecord
|
4
|
+
belongs_to :quotation
|
5
|
+
belongs_to :rfq_item
|
6
|
+
belongs_to :product
|
7
|
+
|
8
|
+
validates :quantity, presence: true, numericality: { greater_than: 0 }
|
9
|
+
validates :unit_price, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
10
|
+
validates :unit, presence: true
|
11
|
+
validates :subtotal, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
12
|
+
|
13
|
+
before_validation :calculate_subtotal
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def calculate_subtotal
|
18
|
+
return unless quantity.present? && unit_price.present?
|
19
|
+
self.subtotal = quantity * unit_price
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Bscf
|
2
|
+
module Core
|
3
|
+
class RequestForQuotation < ApplicationRecord
|
4
|
+
belongs_to :user
|
5
|
+
validates :status, presence: true
|
6
|
+
|
7
|
+
has_many :rfq_items
|
8
|
+
has_many :products, through: :rfq_items
|
9
|
+
|
10
|
+
enum :status, { draft: 0, submitted: 1, awaiting_confirmation: 2, confirmed: 3, converted: 4 }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Bscf
|
2
|
+
module Core
|
3
|
+
class User < ApplicationRecord
|
4
|
+
has_secure_password
|
5
|
+
|
6
|
+
has_one :user_profile
|
7
|
+
has_many :user_roles
|
8
|
+
has_many :roles, through: :user_roles
|
9
|
+
|
10
|
+
has_many :orders_placed, class_name: "Bscf::Core::Order", foreign_key: "ordered_by_id"
|
11
|
+
has_many :orders_received, class_name: "Bscf::Core::Order", foreign_key: "ordered_to_id"
|
12
|
+
|
13
|
+
validates :first_name, presence: true
|
14
|
+
validates :middle_name, presence: true
|
15
|
+
validates :last_name, presence: true
|
16
|
+
validates :password, presence: true
|
17
|
+
validates :phone_number, presence: true, uniqueness: true
|
18
|
+
validates :email, presence: true, uniqueness: true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Bscf
|
2
|
+
module Core
|
3
|
+
class UserProfile < ApplicationRecord
|
4
|
+
belongs_to :user
|
5
|
+
belongs_to :address
|
6
|
+
belongs_to :verified_by, class_name: "User", optional: true
|
7
|
+
|
8
|
+
validates :date_of_birth, presence: true
|
9
|
+
validates :nationality, presence: true
|
10
|
+
validates :occupation, presence: true
|
11
|
+
validates :source_of_funds, presence: true
|
12
|
+
validates :gender, presence: true
|
13
|
+
|
14
|
+
enum :gender, {
|
15
|
+
male: 0,
|
16
|
+
female: 1
|
17
|
+
}
|
18
|
+
|
19
|
+
enum :kyc_status, {
|
20
|
+
pending: 0,
|
21
|
+
approved: 1,
|
22
|
+
rejected: 2
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Bscf
|
2
|
+
module Core
|
3
|
+
class VirtualAccount < ApplicationRecord
|
4
|
+
PRODUCT_SCHEMES = %w[SAVINGS CURRENT LOAN].freeze
|
5
|
+
VOUCHER_TYPES = %w[REGULAR SPECIAL TEMPORARY].freeze
|
6
|
+
|
7
|
+
belongs_to :user
|
8
|
+
|
9
|
+
validates :account_number, presence: true, uniqueness: true
|
10
|
+
validates :cbs_account_number, presence: true, uniqueness: true
|
11
|
+
validates :balance, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
12
|
+
validates :interest_rate, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
13
|
+
validates :interest_type, presence: true
|
14
|
+
validates :branch_code, presence: true
|
15
|
+
validates :product_scheme, presence: true, inclusion: { in: PRODUCT_SCHEMES }
|
16
|
+
validates :voucher_type, presence: true, inclusion: { in: VOUCHER_TYPES }
|
17
|
+
validates :status, presence: true
|
18
|
+
|
19
|
+
enum :interest_type, {
|
20
|
+
simple: 0,
|
21
|
+
compound: 1
|
22
|
+
}
|
23
|
+
|
24
|
+
enum :status, {
|
25
|
+
pending: 0,
|
26
|
+
active: 1,
|
27
|
+
suspended: 2,
|
28
|
+
closed: 3
|
29
|
+
}
|
30
|
+
|
31
|
+
before_validation :generate_account_number, on: :create
|
32
|
+
|
33
|
+
scope :active_accounts, -> { where(active: true, status: :active) }
|
34
|
+
scope :by_branch, ->(code) { where(branch_code: code) }
|
35
|
+
scope :by_product, ->(scheme) { where(product_scheme: scheme) }
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def generate_account_number
|
40
|
+
return if account_number.present?
|
41
|
+
|
42
|
+
last_seq = self.class.maximum(:account_number).to_s[-6..-1].to_i
|
43
|
+
seq = (last_seq + 1).to_s.rjust(6, "0")
|
44
|
+
self.account_number = "#{branch_code}#{product_scheme}#{voucher_type}#{seq}"
|
45
|
+
end
|
46
|
+
|
47
|
+
has_many :sent_transactions, class_name: "Bscf::Core::VirtualAccountTransaction",
|
48
|
+
foreign_key: "from_account_id", dependent: :restrict_with_error
|
49
|
+
has_many :received_transactions, class_name: "Bscf::Core::VirtualAccountTransaction",
|
50
|
+
foreign_key: "to_account_id", dependent: :restrict_with_error
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module Bscf
|
2
|
+
module Core
|
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
|
6
|
+
|
7
|
+
validates :from_account_id, presence: true, if: :requires_from_account?
|
8
|
+
validates :to_account_id, presence: true, if: :requires_to_account?
|
9
|
+
validates :amount, presence: true, numericality: { greater_than: 0 }
|
10
|
+
validates :transaction_type, presence: true
|
11
|
+
validates :status, presence: true
|
12
|
+
validates :reference_number, presence: true, uniqueness: true
|
13
|
+
|
14
|
+
enum :transaction_type, {
|
15
|
+
transfer: 0,
|
16
|
+
deposit: 1,
|
17
|
+
withdrawal: 2
|
18
|
+
}
|
19
|
+
|
20
|
+
enum :status, {
|
21
|
+
pending: 0,
|
22
|
+
completed: 1,
|
23
|
+
failed: 2,
|
24
|
+
cancelled: 3
|
25
|
+
}
|
26
|
+
|
27
|
+
before_validation :generate_reference_number, on: :create
|
28
|
+
validate :validate_transaction, on: :create
|
29
|
+
|
30
|
+
def process!
|
31
|
+
return false unless pending?
|
32
|
+
|
33
|
+
ActiveRecord::Base.transaction do
|
34
|
+
process_transaction
|
35
|
+
update!(status: :completed)
|
36
|
+
end
|
37
|
+
true
|
38
|
+
rescue StandardError => e
|
39
|
+
update(status: :failed)
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
43
|
+
def cancel!
|
44
|
+
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
|
+
|
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
|
68
|
+
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
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
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
|
104
|
+
|
105
|
+
def validate_deposit
|
106
|
+
return unless to_account
|
107
|
+
errors.add(:to_account, "must be active") unless to_account.active?
|
108
|
+
end
|
109
|
+
|
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
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
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
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
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)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
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)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def generate_reference_number
|
150
|
+
return if reference_number.present?
|
151
|
+
|
152
|
+
timestamp = Time.current.strftime("%Y%m%d%H%M%S")
|
153
|
+
random = SecureRandom.hex(3)
|
154
|
+
self.reference_number = "TXN#{timestamp}#{random}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreateBscfCoreUsers < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :bscf_core_users do |t|
|
4
|
+
t.string :first_name, null: false
|
5
|
+
t.string :middle_name, null: false
|
6
|
+
t.string :last_name, null: false
|
7
|
+
t.string :email, null: false
|
8
|
+
t.string :phone_number, null: false
|
9
|
+
t.string :password_digest, null: false
|
10
|
+
|
11
|
+
t.index :email, unique: true
|
12
|
+
t.index :phone_number, unique: true
|
13
|
+
|
14
|
+
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateBscfCoreUserProfiles < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :bscf_core_user_profiles do |t|
|
4
|
+
t.references :user, null: false, foreign_key: { to_table: :bscf_core_users }
|
5
|
+
t.date :date_of_birth, null: false
|
6
|
+
t.string :nationality, null: false
|
7
|
+
t.string :occupation, null: false
|
8
|
+
t.string :source_of_funds, null: false
|
9
|
+
t.integer :kyc_status, default: 0
|
10
|
+
t.integer :gender, null: false
|
11
|
+
t.datetime :verified_at
|
12
|
+
t.references :verified_by, null: true, foreign_key: { to_table: :bscf_core_users }
|
13
|
+
t.references :address, null: false, foreign_key: { to_table: :bscf_core_addresses }
|
14
|
+
t.string :fayda_id
|
15
|
+
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateBscfCoreAddresses < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :bscf_core_addresses do |t|
|
4
|
+
t.string :city
|
5
|
+
t.string :sub_city
|
6
|
+
t.string :woreda
|
7
|
+
t.string :latitude
|
8
|
+
t.string :longitude
|
9
|
+
t.string :house_number
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class CreateBscfCoreUserRoles < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :bscf_core_user_roles do |t|
|
4
|
+
t.references :user, null: false, foreign_key: { to_table: :bscf_core_users }
|
5
|
+
t.references :role, null: false, foreign_key: { to_table: :bscf_core_roles }
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class CreateBscfCoreVirtualAccounts < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :bscf_core_virtual_accounts do |t|
|
4
|
+
t.references :user, null: false, foreign_key: { to_table: :bscf_core_users }
|
5
|
+
t.string :account_number, null: false
|
6
|
+
t.string :cbs_account_number, null: false
|
7
|
+
t.decimal :balance, null: false, default: 0
|
8
|
+
t.decimal :interest_rate, null: false, default: 0
|
9
|
+
t.integer :interest_type, null: false, default: 0
|
10
|
+
t.boolean :active, null: false, default: true
|
11
|
+
t.string :branch_code, null: false
|
12
|
+
t.string :product_scheme, null: false
|
13
|
+
t.string :voucher_type, null: false
|
14
|
+
t.integer :status, null: false, default: 0
|
15
|
+
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
|
19
|
+
add_index :bscf_core_virtual_accounts, :account_number, unique: true
|
20
|
+
add_index :bscf_core_virtual_accounts, :cbs_account_number, unique: true
|
21
|
+
add_index :bscf_core_virtual_accounts, :branch_code
|
22
|
+
add_index :bscf_core_virtual_accounts, [ :user_id, :account_number ]
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateBscfCoreProducts < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :bscf_core_products do |t|
|
4
|
+
t.string :sku, null: false
|
5
|
+
t.string :name, null: false
|
6
|
+
t.string :description, null: false
|
7
|
+
t.references :category, null: false, foreign_key: { to_table: :bscf_core_categories }
|
8
|
+
t.decimal :base_price, null: false, default: 0.0
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
add_index :bscf_core_products, :sku, unique: true
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateBscfCoreBusinesses < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :bscf_core_businesses do |t|
|
4
|
+
t.references :user, null: false, foreign_key: { to_table: :bscf_core_users }
|
5
|
+
t.string :business_name, null: false
|
6
|
+
t.string :tin_number, null: false
|
7
|
+
t.integer :business_type, null: false, default: 0
|
8
|
+
t.datetime :verified_at
|
9
|
+
t.integer :verification_status, null: false, default: 0
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class CreateBscfCoreRequestForQuotations < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :bscf_core_request_for_quotations do |t|
|
4
|
+
t.references :user, null: false, foreign_key: { to_table: :bscf_core_users }
|
5
|
+
t.integer :status, null: false, default: 0
|
6
|
+
t.text :notes
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateBscfCoreRfqItems < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :bscf_core_rfq_items do |t|
|
4
|
+
t.references :request_for_quotation, null: false, foreign_key: { to_table: :bscf_core_request_for_quotations }
|
5
|
+
t.references :product, null: false, foreign_key: { to_table: :bscf_core_products }
|
6
|
+
t.float :quantity, null: false
|
7
|
+
t.text :notes
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|