diff --git a/openapi.yaml b/openapi.yaml index 9c1d0d2d..249d8fbb 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -4932,6 +4932,10 @@ paths: responses: '200': description: Fixed pricing distribution retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionResponse' /superuser/invoicing/period/distribution/wash-subscriptions: get: @@ -6488,6 +6492,10 @@ paths: responses: '200': description: Current weather retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/WeatherApiObjectResponse' /modules/weatherapi/forecast: get: @@ -6514,6 +6522,10 @@ paths: responses: '200': description: Forecast weather retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/WeatherApiObjectResponse' /modules/weatherapi/search: get: @@ -6532,6 +6544,10 @@ paths: responses: '200': description: Location search results retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/WeatherApiObjectResponse' /departments/weather: get: @@ -6562,6 +6578,7 @@ paths: type: array items: $ref: '#/components/schemas/DepartmentWeatherTimelineEntry' + $ref: '#/components/schemas/DepartmentWeatherTimelineResponse' /modules/entra/users: get: @@ -8332,6 +8349,27 @@ components: $ref: '#/components/schemas/DepartmentWeatherStatus' required: [time, weather, washes, hours, status] + WeatherApiObjectResponse: + allOf: + - $ref: '#/components/schemas/ModuleConfigEnvelopeBase' + - type: object + properties: + data: + type: object + additionalProperties: true + required: [data] + + DepartmentWeatherTimelineResponse: + allOf: + - $ref: '#/components/schemas/ModuleConfigEnvelopeBase' + - type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/DepartmentWeatherTimelineEntry' + required: [data] + ModuleConfigEntry: type: object properties: @@ -8771,6 +8809,176 @@ components: - internal_total - order_ids + InvoicingFixedPricingDistributionResponse: + type: object + properties: + success: + type: boolean + example: true + data: + type: array + items: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionCustomer' + meta: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionMeta' + includes: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionIncludes' + required: + - success + - data + - meta + - includes + + InvoicingFixedPricingDistributionCustomer: + type: object + properties: + id: + type: integer + customer_number: + type: integer + customer_name: + type: string + transactions: + type: array + items: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionTransaction' + requires_action: + type: boolean + meta: + type: object + properties: + fixed_pricing: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionFixedPricing' + required: + - fixed_pricing + required: + - id + - customer_number + - customer_name + - transactions + - requires_action + - meta + + InvoicingFixedPricingDistributionTransaction: + type: object + properties: + id: + type: integer + date: + type: string + description: Datetime in `YYYY-MM-DD HH:mm:ss` format. + example: '2026-02-02 10:43:41' + amount: + type: number + booked: + type: boolean + excluded: + type: boolean + required: + - id + - date + - amount + - booked + - excluded + + InvoicingFixedPricingDistributionFixedPricing: + type: object + properties: + customer_number: + type: integer + price: + type: number + description: + type: string + original_price: + type: number + department_totals: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionNumberMapOrEmptyArray' + department_totals_relative: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionNumberMapOrEmptyArray' + required: + - customer_number + - price + - description + - original_price + - department_totals + - department_totals_relative + + InvoicingFixedPricingDistributionMeta: + type: object + properties: + date_from: + type: string + description: Datetime in `YYYY-MM-DD HH:mm:ss` format. + example: '2026-02-01 00:00:00' + date_to: + type: string + description: Datetime in `YYYY-MM-DD HH:mm:ss` format. + example: '2026-02-28 23:59:59' + required: + - date_from + - date_to + + InvoicingFixedPricingDistributionIncludes: + type: object + properties: + debug_invoicing_period_customers_with_orders_in_date_range: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionExecutionTime' + debug_invoicing_period_process_customer_numbers: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionExecutionTime' + debug_invoicing_period_get_transactions_for_customers_in_date_range: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionExecutionTime' + debug_invoicing_period_calculate_transaction_totals: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionExecutionTime' + debug_invoicing_period_construct_customer_objects: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionExecutionTime' + collective_fixed_pricing_results: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionCollectiveResults' + additionalProperties: true + + InvoicingFixedPricingDistributionExecutionTime: + type: object + properties: + execution_time: + type: number + required: + - execution_time + + InvoicingFixedPricingDistributionCollectiveResults: + type: object + properties: + total_fixed_price: + type: number + total_original_price: + type: number + total_department_totals: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionNumberMapOrEmptyArray' + total_department_totals_relative: + $ref: '#/components/schemas/InvoicingFixedPricingDistributionNumberMapOrEmptyArray' + total_department_totals_parsed: + type: object + additionalProperties: + type: number + total_department_totals_relative_parsed: + type: object + additionalProperties: + type: number + required: + - total_fixed_price + - total_original_price + - total_department_totals + - total_department_totals_relative + - total_department_totals_parsed + - total_department_totals_relative_parsed + + InvoicingFixedPricingDistributionNumberMapOrEmptyArray: + oneOf: + - type: object + additionalProperties: + type: number + - type: array + maxItems: 0 + SelfServeLaneStatus: type: object properties: diff --git a/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/InvoicingBillingPeriodStatistics.vue b/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/InvoicingBillingPeriodStatistics.vue index 6f7842f0..8638b17b 100644 --- a/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/InvoicingBillingPeriodStatistics.vue +++ b/src/views/dashboards/superUserDashboard/InvoicingBillingPeriod/displays/layout/InvoicingBillingPeriodStatistics.vue @@ -143,6 +143,35 @@ watch( } ); +const getDepartmentRelativeBookedAmount = (department: any, distribution: any) => { + if (distribution.total_fixed_price === 0) { + return 0; + } + /** + * This takes the total relative booked amount for each department, and then calculates the relative booked amount for the department 75. + * Meaning if: + * department1 = 1000 + * department2 = 2000 + * total booked amount = 6000 + * Then department1 relative booked amount = (1000 / 3000) * 6000 = 2000 + * and department2 relative booked amount = (2000 / 3000) * 6000 = 4000 + */ + const department_original_price = distribution.total_department_totals[department.id] || 0; + const total_original_price = distribution.total_original_price || 0; + const total_booked_amount = view.computed.currentViewTotalNetAmountBooked.value || 0; + const relative_booked_amount = (department_original_price / total_original_price) * total_booked_amount; + return Math.round(relative_booked_amount); + //return SessionUser.functions.currency.toLocal(Math.round(relative_booked_amount)); +}; + +const getTotalAmountDistributed = (distribution: { total_department_totals_parsed: { [s: string]: unknown; } | ArrayLike; total_original_price: number; }) => { + const departments_original_price = Object.values(distribution.total_department_totals_parsed).reduce((acc, value) => acc + value, 0); + const total_original_price = distribution.total_original_price || 0; + const total_booked_amount = view.computed.currentViewTotalNetAmountBooked.value || 0; + const total_amount_distributed = (departments_original_price / total_original_price) * total_booked_amount; + return SessionUser.functions.currency.toLocal(Math.round(total_amount_distributed)); +}; + @@ -363,11 +395,12 @@ watch( {{ SessionUser.functions.currency.toLocal(fixed_pricing_department_distribution.total_original_price) }} {{ SessionUser.functions.currency.toLocal(fixed_pricing_department_distribution.total_fixed_price) }} {{ getPercentageOfTotal(fixed_pricing_department_distribution.total_fixed_price, fixed_pricing_department_distribution.total_original_price) }}% - {{ SessionUser.functions.currency.toLocal(view.computed.currentViewTotalNetAmountBooked.value) }} + 100% + {{ view.computed.currentViewTotalNetAmountBooked.value }} (Distributed: {{ getTotalAmountDistributed(fixed_pricing_department_distribution) }}) @@ -435,10 +471,11 @@ watch( Total {{ SessionUser.functions.currency.toLocal(vehicleSubscriptionDistribution.total_subscription_price) }} 100% + {{ SessionUser.functions.currency.toLocal(view.computed.currentViewTotalNetAmountBooked.value) }}