bscf-core 0.4.5 → 0.4.7

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: '0171058c46dc8d7414df3691156540ceb699ae9cf7b7c6a1970aea4682be4e95'
4
- data.tar.gz: 9721c2d1deadb668511cf9de47ca0a1394ebaf68cd39fede4860aea9e8afd65b
3
+ metadata.gz: 8cf47c7e66d0f00820cfd5175bb4d0dcaf7059018bf48f22a60b41014d7042ff
4
+ data.tar.gz: f688c46d920deba1e26a836ebabe17277591dd67b9b1bd4d3bbc0c415ece887a
5
5
  SHA512:
6
- metadata.gz: afb94496a36fb631222f150ef5969e3445b9c586fb7c359cccceff3fc3af20ba5aa687ca70510b94d9772b60219f9e351abed4398a5429a38a4308f2feebd6f6
7
- data.tar.gz: 2b3a24dccf82b5f56878ce5a598da8dc081b37f5b2d3a9616cd29a9acc2e755eb7dd6523edf50a40119fd7e37484fa548a22cee47acf578da43aadf1305c8710
6
+ metadata.gz: dc807f5982ce22a1ee9d952331707fe9a11e4d6295d507d0a8695971b0f8d3d12467e96069754d12a5ac54cd01c05210032d423ce2066e92d5fbeecb6e8be656
7
+ data.tar.gz: 3c1f6a338140d61b4942767f4cc54fbb67cdb69195b9847d7fba5d28f5d63ab015031243a122fd319fbf572221a6ccd1fc5673262b0606cb41f3487dcd0fc011
@@ -5,14 +5,13 @@ module Bscf
5
5
 
6
6
  # Add associations for delivery orders and items
7
7
  has_many :delivery_order_pickups, class_name: "Bscf::Core::DeliveryOrder", foreign_key: "pickup_address_id"
8
- has_many :delivery_order_dropoffs, class_name: "Bscf::Core::DeliveryOrder", foreign_key: "dropoff_address_id"
9
8
  has_many :delivery_order_item_pickups, class_name: "Bscf::Core::DeliveryOrderItem", foreign_key: "pickup_address_id"
10
9
  has_many :delivery_order_item_dropoffs, class_name: "Bscf::Core::DeliveryOrderItem", foreign_key: "dropoff_address_id"
11
10
 
12
11
  validates :latitude, :longitude, presence: true, if: :requires_coordinates?
13
12
 
14
13
  def coordinates
15
- [latitude.to_f, longitude.to_f] if latitude.present? && longitude.present?
14
+ [ latitude.to_f, longitude.to_f ] if latitude.present? && longitude.present?
16
15
  end
17
16
 
18
17
  def full_address
@@ -24,8 +23,7 @@ module Bscf
24
23
  def requires_coordinates?
25
24
  # Determine when coordinates are required
26
25
  # For delivery addresses, they should always be required
27
- delivery_order_pickups.any? || delivery_order_dropoffs.any? ||
28
- delivery_order_item_pickups.any? || delivery_order_item_dropoffs.any?
26
+ delivery_order_pickups.any? || delivery_order_item_pickups.any? || delivery_order_item_dropoffs.any?
29
27
  end
30
28
  end
31
29
  end
@@ -1,14 +1,13 @@
1
1
  module Bscf
2
2
  module Core
3
3
  class BusinessDocument < ApplicationRecord
4
- belongs_to :business
4
+ belongs_to :user
5
5
  has_one_attached :file
6
6
 
7
7
  before_validation :format_document_name
8
8
 
9
9
  validates :document_number, presence: true
10
10
  validates :document_name, presence: true
11
- validates :business_id, presence: true
12
11
  validates :verified_at, presence: true, if: :is_verified?
13
12
  validates :file, presence: true
14
13
  validate :block_executable_files
@@ -3,7 +3,6 @@ module Bscf
3
3
  class DeliveryOrder < ApplicationRecord
4
4
  has_many :orders
5
5
  belongs_to :pickup_address, class_name: "Bscf::Core::Address"
6
- belongs_to :dropoff_address, class_name: "Bscf::Core::Address"
7
6
  belongs_to :driver, class_name: "Bscf::Core::User", optional: true
8
7
 
9
8
  has_many :delivery_order_items, dependent: :destroy
@@ -0,0 +1,34 @@
1
+ module Bscf
2
+ module Core
3
+ class Invoice < ApplicationRecord
4
+ belongs_to :order
5
+ has_many :payments, dependent: :destroy
6
+
7
+ validates :invoice_number, presence: true, uniqueness: true
8
+ validates :amount, :tax_amount, :discount_amount, :total_amount, presence: true,
9
+ numericality: { greater_than_or_equal_to: 0 }
10
+ validates :status, presence: true
11
+
12
+ enum :status, {
13
+ draft: 0,
14
+ issued: 1,
15
+ paid: 2,
16
+ partially_paid: 3,
17
+ overdue: 4,
18
+ cancelled: 5
19
+ }
20
+
21
+ before_validation :generate_invoice_number, on: :create
22
+
23
+ private
24
+
25
+ def generate_invoice_number
26
+ return if invoice_number.present?
27
+
28
+ timestamp = Time.current.strftime("%Y%m%d%H%M%S")
29
+ random_suffix = SecureRandom.hex(3)
30
+ self.invoice_number = "INV#{timestamp}#{random_suffix}"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,21 @@
1
+ module Bscf
2
+ module Core
3
+ class InvoiceItem < ApplicationRecord
4
+ belongs_to :invoice, class_name: "Bscf::Core::Invoice"
5
+ belongs_to :order_item, class_name: "Bscf::Core::OrderItem"
6
+
7
+ validates :description, :quantity, :unit_price, :subtotal, presence: true
8
+ validates :quantity, numericality: { greater_than: 0 }
9
+ validates :unit_price, :subtotal, numericality: { greater_than_or_equal_to: 0 }
10
+
11
+ before_save :calculate_subtotal
12
+
13
+ private
14
+
15
+ def calculate_subtotal
16
+ self.unit_price = order_item.unit_price
17
+ self.subtotal = quantity * unit_price if quantity.present? && unit_price.present?
18
+ end
19
+ end
20
+ end
21
+ end
@@ -5,6 +5,7 @@ module Bscf
5
5
  belongs_to :ordered_to, class_name: "Bscf::Core::User", optional: true
6
6
  belongs_to :quotation, optional: true
7
7
  belongs_to :delivery_order, optional: true
8
+ belongs_to :drop_off_address, class_name: "Bscf::Core::Address", optional: true
8
9
  has_many :order_items, dependent: :destroy
9
10
  validates :order_type, :status, presence: true
10
11
 
@@ -0,0 +1,47 @@
1
+ module Bscf
2
+ module Core
3
+ class Payment < ApplicationRecord
4
+ belongs_to :invoice
5
+ belongs_to :virtual_account_transaction, class_name: "Bscf::Core::VirtualAccountTransaction", optional: true
6
+
7
+ validates :amount, presence: true, numericality: { greater_than: 0 }
8
+ validates :payment_method, :status, presence: true
9
+ validates :reference_number, presence: true, uniqueness: true
10
+
11
+ enum :payment_method, {
12
+ cash: 0,
13
+ virtual_account: 1
14
+ }
15
+
16
+ enum :status, {
17
+ pending: 0,
18
+ completed: 1,
19
+ failed: 2,
20
+ refunded: 3
21
+ }
22
+
23
+ before_validation :generate_reference_number, on: :create
24
+ after_save :update_invoice_status, if: -> { saved_change_to_status? && status == "completed" }
25
+
26
+ private
27
+
28
+ def generate_reference_number
29
+ return if reference_number.present?
30
+
31
+ timestamp = Time.current.strftime("%Y%m%d%H%M%S")
32
+ random_suffix = SecureRandom.hex(3)
33
+ self.reference_number = "PAY#{timestamp}#{random_suffix}"
34
+ end
35
+
36
+ def update_invoice_status
37
+ total_paid = invoice.payments.completed.sum(:amount)
38
+
39
+ if total_paid >= invoice.total_amount
40
+ invoice.update(status: :paid)
41
+ elsif total_paid > 0
42
+ invoice.update(status: :partially_paid)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,17 @@
1
+ class CreateBscfCoreInvoices < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :bscf_core_invoices do |t|
4
+ t.references :order, null: false, foreign_key: { to_table: :bscf_core_orders }
5
+ t.string :invoice_number, null: false, index: { unique: true }
6
+ t.decimal :amount, precision: 10, scale: 2, null: false
7
+ t.decimal :tax_amount, precision: 10, scale: 2, null: false
8
+ t.decimal :discount_amount, precision: 10, scale: 2, null: false
9
+ t.decimal :total_amount, precision: 10, scale: 2, null: false
10
+ t.datetime :due_date
11
+ t.integer :status, null: false, default: 0
12
+ t.text :notes
13
+
14
+ t.timestamps
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ class CreateBscfCoreInvoiceItems < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :bscf_core_invoice_items do |t|
4
+ t.references :invoice, null: false, foreign_key: { to_table: :bscf_core_invoices }
5
+ t.references :order_item, null: false, foreign_key: { to_table: :bscf_core_order_items }
6
+ t.string :description
7
+ t.integer :quantity, null: false
8
+ t.decimal :unit_price, null: false, precision: 10, scale: 2
9
+ t.decimal :tax_rate, precision: 10, scale: 2
10
+ t.decimal :tax_amount, precision: 10, scale: 2
11
+ t.decimal :discount_amount, precision: 10, scale: 2
12
+ t.decimal :subtotal, null: false, precision: 10, scale: 2, default: 0
13
+
14
+ t.timestamps
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ class CreateBscfCorePayments < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :bscf_core_payments do |t|
4
+ t.references :invoice, null: false, foreign_key: { to_table: :bscf_core_invoices }
5
+ t.references :virtual_account_transaction, null: true, foreign_key: { to_table: :bscf_core_virtual_account_transactions }
6
+ t.decimal :amount, precision: 10, scale: 2, null: false
7
+ t.integer :payment_method, null: false, default: 0
8
+ t.datetime :payment_date
9
+ t.string :reference_number, null: false
10
+ t.integer :status, null: false, default: 0
11
+ t.text :notes
12
+
13
+ t.timestamps
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ class AddDropOffAdressToOrders < ActiveRecord::Migration[8.0]
2
+ def change
3
+ add_column :bscf_core_orders, :drop_off_address_id, :bigint
4
+ add_foreign_key :bscf_core_orders, :bscf_core_addresses, column: :drop_off_address_id
5
+ change_column_null :bscf_core_orders, :drop_off_address_id, true
6
+ add_index :bscf_core_orders, :drop_off_address_id, name: "a_on_bscf_core_ord_index"
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ class RemoveDropoffAddressFromDeliveryOrders < ActiveRecord::Migration[8.0]
2
+ def change
3
+ remove_foreign_key :bscf_core_delivery_orders, column: :dropoff_address_id
4
+ remove_index :bscf_core_delivery_orders, :dropoff_address_id
5
+ remove_column :bscf_core_delivery_orders, :dropoff_address_id
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class RenameBusinessIdToUserIdInBscfCoreBusinessDocuments < ActiveRecord::Migration[8.0]
2
+ def change
3
+ remove_foreign_key :bscf_core_business_documents, column: :business_id
4
+ rename_column :bscf_core_business_documents, :business_id, :user_id
5
+ add_foreign_key :bscf_core_business_documents, :bscf_core_users, column: :user_id
6
+ end
7
+ end
@@ -1,5 +1,5 @@
1
1
  module Bscf
2
2
  module Core
3
- VERSION = "0.4.5"
3
+ VERSION = "0.4.7"
4
4
  end
5
5
  end
@@ -1,6 +1,6 @@
1
1
  FactoryBot.define do
2
2
  factory :business_document, class: 'Bscf::Core::BusinessDocument' do
3
- association :business, factory: :business
3
+ user
4
4
  document_number { "DOC-#{SecureRandom.hex(4).upcase}" }
5
5
  document_name { "Business License" }
6
6
  document_description { "Official business license document" }
@@ -1,7 +1,6 @@
1
1
  FactoryBot.define do
2
2
  factory :delivery_order, class: 'Bscf::Core::DeliveryOrder' do
3
3
  association :pickup_address, factory: :address
4
- association :dropoff_address, factory: :address
5
4
  association :driver, factory: :user
6
5
 
7
6
  driver_phone { Faker::PhoneNumber.phone_number }
@@ -0,0 +1,9 @@
1
+ FactoryBot.define do
2
+ factory :invoice_item, class: 'Bscf::Core::InvoiceItem' do
3
+ invoice
4
+ order_item
5
+ description { Faker::Commerce.product_name }
6
+ quantity { Faker::Number.between(from: 1, to: 10) }
7
+ unit_price { Faker::Number.decimal(l_digits: 2, r_digits: 2) }
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ FactoryBot.define do
2
+ factory :invoice, class: 'Bscf::Core::Invoice' do
3
+ order
4
+ amount { Faker::Number.decimal(l_digits: 3, r_digits: 2) }
5
+ tax_amount { Faker::Number.decimal(l_digits: 2, r_digits: 2) }
6
+ discount_amount { Faker::Number.decimal(l_digits: 1, r_digits: 2) }
7
+ total_amount { amount + tax_amount - discount_amount }
8
+ due_date { Time.current + 30.days }
9
+ status { :draft }
10
+ notes { Faker::Lorem.paragraph }
11
+ end
12
+ end
@@ -7,5 +7,6 @@ FactoryBot.define do
7
7
  status { :draft }
8
8
  total_amount { Faker::Number.between(from: 100, to: 1000) }
9
9
  delivery_order { nil }
10
+ association :drop_off_address, factory: :address
10
11
  end
11
12
  end
@@ -0,0 +1,12 @@
1
+ FactoryBot.define do
2
+ factory :payment, class: 'Bscf::Core::Payment' do
3
+ invoice
4
+ virtual_account_transaction { nil }
5
+ amount { Faker::Number.decimal(l_digits: 3, r_digits: 2) }
6
+ payment_method { :virtual_account }
7
+ status { :pending }
8
+ reference_number { "PAY#{Time.current.strftime('%Y%m%d%H%M%S')}#{SecureRandom.hex(3)}" }
9
+ payment_date { Time.current }
10
+ notes { Faker::Lorem.sentence }
11
+ end
12
+ 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.4.5
4
+ version: 0.4.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asrat
@@ -293,9 +293,12 @@ files:
293
293
  - app/models/bscf/core/category.rb
294
294
  - app/models/bscf/core/delivery_order.rb
295
295
  - app/models/bscf/core/delivery_order_item.rb
296
+ - app/models/bscf/core/invoice.rb
297
+ - app/models/bscf/core/invoice_item.rb
296
298
  - app/models/bscf/core/marketplace_listing.rb
297
299
  - app/models/bscf/core/order.rb
298
300
  - app/models/bscf/core/order_item.rb
301
+ - app/models/bscf/core/payment.rb
299
302
  - app/models/bscf/core/product.rb
300
303
  - app/models/bscf/core/quotation.rb
301
304
  - app/models/bscf/core/quotation_item.rb
@@ -314,7 +317,6 @@ files:
314
317
  - app/services/bscf/core/token_service.rb
315
318
  - app/services/bscf/core/transaction_service.rb
316
319
  - config/database.yml
317
- - config/master.key
318
320
  - config/routes.rb
319
321
  - db/migrate/20250326065606_create_bscf_core_users.rb
320
322
  - db/migrate/20250326075111_create_bscf_core_roles.rb
@@ -350,9 +352,14 @@ files:
350
352
  - db/migrate/20250606100158_add_product_to_market_place_listings.rb
351
353
  - db/migrate/20250609180530_add_accounting_fields_to_virtual_account_transactions.rb
352
354
  - db/migrate/20250610120351_update_delivery_tables.rb
355
+ - db/migrate/20250616121538_create_bscf_core_invoices.rb
356
+ - db/migrate/20250616123937_create_bscf_core_invoice_items.rb
357
+ - db/migrate/20250616131835_create_bscf_core_payments.rb
353
358
  - db/migrate/20250616134209_update_address_coordinates_type.rb
354
359
  - db/migrate/20250616145522_add_position_to_delivery_order_items.rb
355
- - db/migrate/20250619124144_add_optimized_route_to_delivery_orders.rb
360
+ - db/migrate/20250623113112_add_drop_off_adress_to_orders.rb
361
+ - db/migrate/20250623115615_remove_dropoff_address_from_delivery_orders.rb
362
+ - db/migrate/20250624062746_rename_business_id_to_user_id_in_bscf_core_business_documents.rb
356
363
  - lib/bscf/core.rb
357
364
  - lib/bscf/core/engine.rb
358
365
  - lib/bscf/core/version.rb
@@ -366,9 +373,12 @@ files:
366
373
  - spec/factories/bscf/core/categories.rb
367
374
  - spec/factories/bscf/core/delivery_order_items.rb
368
375
  - spec/factories/bscf/core/delivery_orders.rb
376
+ - spec/factories/bscf/core/invoice_items.rb
377
+ - spec/factories/bscf/core/invoices.rb
369
378
  - spec/factories/bscf/core/marketplace_listings.rb
370
379
  - spec/factories/bscf/core/order_items.rb
371
380
  - spec/factories/bscf/core/orders.rb
381
+ - spec/factories/bscf/core/payments.rb
372
382
  - spec/factories/bscf/core/products.rb
373
383
  - spec/factories/bscf/core/quotation_items.rb
374
384
  - spec/factories/bscf/core/quotations.rb
data/config/master.key DELETED
@@ -1 +0,0 @@
1
- 3009aef5af3ca1ddb654f74ad2ac7d5a
@@ -1,5 +0,0 @@
1
- class AddOptimizedRouteToDeliveryOrders < ActiveRecord::Migration[8.0]
2
- def change
3
- add_column :bscf_core_delivery_orders, :optimized_route, :jsonb
4
- end
5
- end