mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
(feat) usage history of prepaid packs
This commit is contained in:
parent
ed3353ce7c
commit
9b4c47d733
@ -1,6 +1,7 @@
|
||||
# Changelog Fab-manager
|
||||
|
||||
- Improved upgrade script
|
||||
- Keep usage history of prepaid packs
|
||||
- OpenAPI reservation endpoint can be filtered by date
|
||||
- OpenAPI users endpoint now returns the ID of the InvoicingProfile
|
||||
- Fix a bug: wrong counting of minutes used when using a prepaid pack
|
||||
|
@ -6,6 +6,9 @@ class API::UserPacksController < API::ApiController
|
||||
|
||||
def index
|
||||
@user_packs = PrepaidPackService.user_packs(user, item)
|
||||
|
||||
@history = params[:history] == 'true'
|
||||
@user_packs = @user_packs.includes(:prepaid_pack_reservations) if @history
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -41,7 +41,7 @@ const PrepaidPacksPanel: React.FC<PrepaidPacksPanelProps> = ({ user, onError })
|
||||
const { handleSubmit, control, formState } = useForm<{ machine_id: number }>();
|
||||
|
||||
useEffect(() => {
|
||||
UserPackAPI.index({ user_id: user.id })
|
||||
UserPackAPI.index({ user_id: user.id, history: true })
|
||||
.then(setUserPacks)
|
||||
.catch(onError);
|
||||
SettingAPI.get('renew_pack_threshold')
|
||||
@ -106,7 +106,7 @@ const PrepaidPacksPanel: React.FC<PrepaidPacksPanelProps> = ({ user, onError })
|
||||
*/
|
||||
const onPackBoughtSuccess = () => {
|
||||
togglePacksModal();
|
||||
UserPackAPI.index({ user_id: user.id })
|
||||
UserPackAPI.index({ user_id: user.id, history: true })
|
||||
.then(setUserPacks)
|
||||
.catch(onError);
|
||||
};
|
||||
@ -128,16 +128,18 @@ const PrepaidPacksPanel: React.FC<PrepaidPacksPanelProps> = ({ user, onError })
|
||||
<p className="countdown"><span>{(pack.prepaid_pack.minutes - pack.minutes_used) / 60}H</span> / {pack.prepaid_pack.minutes / 60}H</p>
|
||||
</div>
|
||||
</div>
|
||||
{ /* usage history is not saved for now
|
||||
{pack.history?.length > 0 &&
|
||||
<div className="prepaid-packs-list is-history">
|
||||
<span className='prepaid-packs-list-label'>{t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.history')}</span>
|
||||
|
||||
<div className='prepaid-packs-list-item'>
|
||||
<p className='name'>00{t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.consumed_hours')}</p>
|
||||
<p className="date">00/00/00</p>
|
||||
</div>
|
||||
{pack.history.map(prepaidReservation => (
|
||||
<div className='prepaid-packs-list-item' key={prepaidReservation.id}>
|
||||
<p className='name'>{t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.consumed_hours', { COUNT: prepaidReservation.consumed_minutes / 60 })}</p>
|
||||
<p className="date">{FormatLib.date(prepaidReservation.reservation_date)}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
*/ }
|
||||
}
|
||||
</div>
|
||||
))}
|
||||
|
||||
|
@ -4,7 +4,8 @@ import { ApiFilter } from './api';
|
||||
export interface UserPackIndexFilter extends ApiFilter {
|
||||
user_id: number,
|
||||
priceable_type?: string,
|
||||
priceable_id?: number
|
||||
priceable_id?: number,
|
||||
history?: boolean
|
||||
}
|
||||
|
||||
export interface UserPack {
|
||||
@ -17,5 +18,11 @@ export interface UserPack {
|
||||
priceable: {
|
||||
name: string
|
||||
}
|
||||
}
|
||||
},
|
||||
history?: Array<{
|
||||
id: number,
|
||||
consumed_minutes: number,
|
||||
reservation_id: number,
|
||||
reservation_date: TDateISO
|
||||
}>
|
||||
}
|
||||
|
7
app/models/prepaid_pack_reservation.rb
Normal file
7
app/models/prepaid_pack_reservation.rb
Normal file
@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Save the association between a Reservation and a PrepaidPack to keep the usage history.
|
||||
class PrepaidPackReservation < ApplicationRecord
|
||||
belongs_to :statistic_profile_prepaid_pack
|
||||
belongs_to :reservation
|
||||
end
|
@ -21,6 +21,8 @@ class Reservation < ApplicationRecord
|
||||
has_many :invoice_items, as: :object, dependent: :destroy
|
||||
has_one :payment_schedule_object, as: :object, dependent: :destroy
|
||||
|
||||
has_many :prepaid_pack_reservations, dependent: :destroy
|
||||
|
||||
validates :reservable_id, :reservable_type, presence: true
|
||||
validate :machine_not_already_reserved, if: -> { reservable.is_a?(Machine) }
|
||||
validate :training_not_fully_reserved, if: -> { reservable.is_a?(Training) }
|
||||
|
@ -8,6 +8,7 @@ class StatisticProfilePrepaidPack < ApplicationRecord
|
||||
|
||||
has_many :invoice_items, as: :object, dependent: :destroy
|
||||
has_one :payment_schedule_object, as: :object, dependent: :destroy
|
||||
has_many :prepaid_pack_reservations, dependent: :restrict_with_error
|
||||
|
||||
before_create :set_expiration_date
|
||||
|
||||
|
@ -7,6 +7,7 @@ class PrepaidPackService
|
||||
# @option filters [Integer] :group_id
|
||||
# @option filters [Integer] :priceable_id
|
||||
# @option filters [String] :priceable_type 'Machine' | 'Space'
|
||||
# @return [ActiveRecord::Relation<PrepaidPack>]
|
||||
def list(filters)
|
||||
packs = PrepaidPack.where(nil)
|
||||
|
||||
@ -25,6 +26,7 @@ class PrepaidPackService
|
||||
# return the not expired packs for the given item bought by the given user
|
||||
# @param user [User]
|
||||
# @param priceable [Machine,Space,NilClass]
|
||||
# @return [ActiveRecord::Relation<StatisticProfilePrepaidPack>]
|
||||
def user_packs(user, priceable = nil)
|
||||
sppp = StatisticProfilePrepaidPack.includes(:prepaid_pack)
|
||||
.references(:prepaid_packs)
|
||||
@ -65,6 +67,7 @@ class PrepaidPackService
|
||||
|
||||
pack_consumed = consumed > pack_available ? pack_available : consumed
|
||||
consumed -= pack_consumed
|
||||
PrepaidPackReservation.create!(statistic_profile_prepaid_pack: pack, reservation: reservation, consumed_minutes: pack_consumed)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -8,4 +8,10 @@ json.array!(@user_packs) do |user_pack|
|
||||
json.extract! user_pack.prepaid_pack.priceable, :name
|
||||
end
|
||||
end
|
||||
if @history
|
||||
json.history user_pack.prepaid_pack_reservations do |ppr|
|
||||
json.extract! ppr, :id, :consumed_minutes, :reservation_id
|
||||
json.reservation_date ppr.reservation.created_at
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -166,7 +166,7 @@ en:
|
||||
end: "Expiry date"
|
||||
countdown: "Countdown"
|
||||
history: "History"
|
||||
consumed_hours: "H consumed"
|
||||
consumed_hours: "{COUNT, plural, =1{1H consumed} other{{COUNT}H consumed}}"
|
||||
cta_info: "You can buy prepaid hours packs to book machines and benefit from discounts. Choose a machine to buy a corresponding pack."
|
||||
select_machine: "Select a machine"
|
||||
cta_button: "Buy a pack"
|
||||
|
@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# From this migration we save the association between a Reservation and a PrepaidPack to keep the
|
||||
# usage history.
|
||||
class CreatePrepaidPackReservations < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :prepaid_pack_reservations do |t|
|
||||
t.references :statistic_profile_prepaid_pack, foreign_key: true, index: { name: 'index_prepaid_pack_reservations_on_sp_prepaid_pack_id' }
|
||||
t.references :reservation, foreign_key: true
|
||||
t.integer :consumed_minutes
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
27
db/schema.rb
27
db/schema.rb
@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2023_03_02_120458) do
|
||||
ActiveRecord::Schema.define(version: 2023_03_09_094535) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "fuzzystrmatch"
|
||||
@ -739,6 +739,17 @@ ActiveRecord::Schema.define(version: 2023_03_02_120458) do
|
||||
t.text "description"
|
||||
end
|
||||
|
||||
create_table "plan_limitations", force: :cascade do |t|
|
||||
t.bigint "plan_id"
|
||||
t.string "limitable_type"
|
||||
t.bigint "limitable_id"
|
||||
t.integer "limit", default: 0, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["limitable_type", "limitable_id"], name: "index_plan_limitations_on_limitable_type_and_limitable_id"
|
||||
t.index ["plan_id"], name: "index_plan_limitations_on_plan_id"
|
||||
end
|
||||
|
||||
create_table "plans", id: :serial, force: :cascade do |t|
|
||||
t.string "name"
|
||||
t.integer "amount"
|
||||
@ -758,6 +769,7 @@ ActiveRecord::Schema.define(version: 2023_03_02_120458) do
|
||||
t.boolean "disabled"
|
||||
t.boolean "monthly_payment"
|
||||
t.bigint "plan_category_id"
|
||||
t.boolean "limiting"
|
||||
t.index ["group_id"], name: "index_plans_on_group_id"
|
||||
t.index ["plan_category_id"], name: "index_plans_on_plan_category_id"
|
||||
end
|
||||
@ -769,6 +781,16 @@ ActiveRecord::Schema.define(version: 2023_03_02_120458) do
|
||||
t.index ["plan_id"], name: "index_plans_availabilities_on_plan_id"
|
||||
end
|
||||
|
||||
create_table "prepaid_pack_reservations", force: :cascade do |t|
|
||||
t.bigint "statistic_profile_prepaid_pack_id"
|
||||
t.bigint "reservation_id"
|
||||
t.integer "consumed_minutes"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["reservation_id"], name: "index_prepaid_pack_reservations_on_reservation_id"
|
||||
t.index ["statistic_profile_prepaid_pack_id"], name: "index_prepaid_pack_reservations_on_sp_prepaid_pack_id"
|
||||
end
|
||||
|
||||
create_table "prepaid_packs", force: :cascade do |t|
|
||||
t.string "priceable_type"
|
||||
t.bigint "priceable_id"
|
||||
@ -1422,7 +1444,10 @@ ActiveRecord::Schema.define(version: 2023_03_02_120458) do
|
||||
add_foreign_key "payment_schedules", "invoicing_profiles", column: "operator_profile_id"
|
||||
add_foreign_key "payment_schedules", "statistic_profiles"
|
||||
add_foreign_key "payment_schedules", "wallet_transactions"
|
||||
add_foreign_key "plan_limitations", "plans"
|
||||
add_foreign_key "plans", "plan_categories"
|
||||
add_foreign_key "prepaid_pack_reservations", "reservations"
|
||||
add_foreign_key "prepaid_pack_reservations", "statistic_profile_prepaid_packs"
|
||||
add_foreign_key "prepaid_packs", "groups"
|
||||
add_foreign_key "prices", "groups"
|
||||
add_foreign_key "prices", "plans"
|
||||
|
@ -307,7 +307,7 @@ namespace :fablab do
|
||||
|
||||
desc '[release 5.8.2] fix prepaid packs minutes_used'
|
||||
task pack_minutes_used: :environment do |_task, _args|
|
||||
StatisticProfilePrepaidPack.where('minutes_used < 0').find_each do |sppp|
|
||||
StatisticProfilePrepaidPack.find_each do |sppp|
|
||||
previous_packs = sppp.statistic_profile.statistic_profile_prepaid_packs
|
||||
.includes(:prepaid_pack)
|
||||
.where(prepaid_packs: { priceable: sppp.prepaid_pack.priceable })
|
||||
@ -342,6 +342,7 @@ namespace :fablab do
|
||||
end
|
||||
end
|
||||
available_minutes -= consumed
|
||||
PrepaidPackReservation.find_or_create_by!(statistic_profile_prepaid_pack: pack, reservation: reservation, consumed_minutes: consumed)
|
||||
end
|
||||
pack.update(minutes_used: pack.prepaid_pack.minutes - available_minutes)
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user