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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/app/models/bscf/core/address.rb +7 -0
  4. data/app/models/bscf/core/business.rb +15 -0
  5. data/app/models/bscf/core/category.rb +11 -0
  6. data/app/models/bscf/core/order.rb +24 -0
  7. data/app/models/bscf/core/order_item.rb +15 -0
  8. data/app/models/bscf/core/product.rb +29 -0
  9. data/app/models/bscf/core/quotation.rb +29 -0
  10. data/app/models/bscf/core/quotation_item.rb +23 -0
  11. data/app/models/bscf/core/request_for_quotation.rb +13 -0
  12. data/app/models/bscf/core/rfq_item.rb +9 -0
  13. data/app/models/bscf/core/role.rb +10 -0
  14. data/app/models/bscf/core/user.rb +21 -0
  15. data/app/models/bscf/core/user_profile.rb +26 -0
  16. data/app/models/bscf/core/user_role.rb +8 -0
  17. data/app/models/bscf/core/virtual_account.rb +53 -0
  18. data/app/models/bscf/core/virtual_account_transaction.rb +158 -0
  19. data/db/migrate/20250326065606_create_bscf_core_users.rb +18 -0
  20. data/db/migrate/20250326075111_create_bscf_core_roles.rb +9 -0
  21. data/db/migrate/20250326080646_create_bscf_core_user_profiles.rb +19 -0
  22. data/db/migrate/20250326081052_create_bscf_core_addresses.rb +14 -0
  23. data/db/migrate/20250326084233_create_bscf_core_user_roles.rb +10 -0
  24. data/db/migrate/20250326085741_create_bscf_core_virtual_accounts.rb +24 -0
  25. data/db/migrate/20250326103305_create_bscf_core_categories.rb +11 -0
  26. data/db/migrate/20250326105652_create_bscf_core_products.rb +14 -0
  27. data/db/migrate/20250326112449_create_bscf_core_businesses.rb +14 -0
  28. data/db/migrate/20250326115203_create_bscf_core_request_for_quotations.rb +11 -0
  29. data/db/migrate/20250326120613_create_bscf_core_rfq_items.rb +12 -0
  30. data/db/migrate/20250326121246_create_bscf_core_bscf_core_virtual_account_transactions.rb +19 -0
  31. data/db/migrate/20250327041651_create_bscf_core_quotations.rb +15 -0
  32. data/db/migrate/20250327044020_create_bscf_core_quotation_items.rb +15 -0
  33. data/db/migrate/20250327102217_create_bscf_core_orders.rb +14 -0
  34. data/db/migrate/20250327112412_create_bscf_core_order_items.rb +14 -0
  35. data/lib/bscf/core/engine.rb +18 -0
  36. data/lib/bscf/core/version.rb +1 -1
  37. data/lib/tasks/release.rake +42 -0
  38. data/spec/dummy/db/schema.rb +246 -0
  39. data/spec/dummy/log/development.log +2060 -0
  40. data/spec/dummy/log/test.log +69259 -0
  41. data/spec/examples.txt +167 -3
  42. data/spec/factories/bscf/core/addresses.rb +10 -0
  43. data/spec/factories/bscf/core/businesses.rb +24 -0
  44. data/spec/factories/bscf/core/categories.rb +16 -0
  45. data/spec/factories/bscf/core/order_items.rb +10 -0
  46. data/spec/factories/bscf/core/orders.rb +10 -0
  47. data/spec/factories/bscf/core/products.rb +8 -0
  48. data/spec/factories/bscf/core/quotation_items.rb +11 -0
  49. data/spec/factories/bscf/core/quotations.rb +28 -0
  50. data/spec/factories/bscf/core/request_for_quotations.rb +7 -0
  51. data/spec/factories/bscf/core/rfq_items.rb +8 -0
  52. data/spec/factories/bscf/core/roles.rb +5 -0
  53. data/spec/factories/bscf/core/user_profiles.rb +15 -0
  54. data/spec/factories/bscf/core/user_roles.rb +6 -0
  55. data/spec/factories/bscf/core/users.rb +10 -0
  56. data/spec/factories/bscf/core/virtual_account_transactions.rb +34 -0
  57. data/spec/factories/bscf/core/virtual_accounts.rb +38 -0
  58. data/spec/models/bscf/core/address_spec.rb +12 -0
  59. data/spec/models/bscf/core/business_spec.rb +64 -0
  60. data/spec/models/bscf/core/category_spec.rb +43 -0
  61. data/spec/models/bscf/core/order_item_spec.rb +26 -0
  62. data/spec/models/bscf/core/order_spec.rb +16 -0
  63. data/spec/models/bscf/core/product_spec.rb +47 -0
  64. data/spec/models/bscf/core/quotation_item_spec.rb +44 -0
  65. data/spec/models/bscf/core/quotation_spec.rb +41 -0
  66. data/spec/models/bscf/core/request_for_quotation_spec.rb +13 -0
  67. data/spec/models/bscf/core/rfq_item_spec.rb +14 -0
  68. data/spec/models/bscf/core/role_spec.rb +14 -0
  69. data/spec/models/bscf/core/user_profile_spec.rb +20 -0
  70. data/spec/models/bscf/core/user_role_spec.rb +13 -0
  71. data/spec/models/bscf/core/user_spec.rb +22 -0
  72. data/spec/models/bscf/core/virtual_account_spec.rb +111 -0
  73. data/spec/models/bscf/core/virtual_account_transaction_spec.rb +133 -0
  74. data/spec/spec_helper.rb +4 -1
  75. data/spec/support/requests/shared_requests.rb +4 -4
  76. metadata +69 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3809381078c320ca29b8e18319a28a57f3ef7536a4db3beab9006d9e697b0a1
4
- data.tar.gz: 413847ec12888e616845d0928fd21eb0391456a0ea0c3de2b695a53bb782b14b
3
+ metadata.gz: 0b265836a53a2c3d1b4c492d064732a6203150366915f479897ee293690414d3
4
+ data.tar.gz: 444ed29066f85fb8b2d0defd0c3c798bac8a657ef09ba6e1d6777204edff7a1f
5
5
  SHA512:
6
- metadata.gz: 7bcd4a81d4536899afec6b26c4cbbe35e3454787e061b42930437284f2a0a5895bb7a4f13a3419f47fe517be670ea56157a9dd1bd53dc571d2669a4917c0625a
7
- data.tar.gz: c1a1571b6f13b3cf1659870257e79ba378ac456f95e9db00b05db3d3c22e426ccc36e6e69e45a6298a91d4d79fba8d7093717a6a9b848f365bffd32320dfdee1
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,7 @@
1
+ module Bscf
2
+ module Core
3
+ class Address < ApplicationRecord
4
+ has_many :user_profiles
5
+ end
6
+ end
7
+ end
@@ -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,9 @@
1
+ module Bscf
2
+ module Core
3
+ class RfqItem < ApplicationRecord
4
+ belongs_to :request_for_quotation
5
+ belongs_to :product
6
+ validates :quantity, presence: true
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module Bscf
2
+ module Core
3
+ class Role < ApplicationRecord
4
+ has_many :user_roles
5
+ has_many :users, through: :user_roles
6
+
7
+ validates :name, presence: true
8
+ end
9
+ end
10
+ 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,8 @@
1
+ module Bscf
2
+ module Core
3
+ class UserRole < ApplicationRecord
4
+ belongs_to :user
5
+ belongs_to :role
6
+ end
7
+ end
8
+ 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,9 @@
1
+ class CreateBscfCoreRoles < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :bscf_core_roles do |t|
4
+ t.string :name, null: false
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ 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,11 @@
1
+ class CreateBscfCoreCategories < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :bscf_core_categories do |t|
4
+ t.string :name, null: false
5
+ t.string :description, null: false
6
+ t.bigint :parent_id
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ 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