The overall goal is to improve the return of the X and Z reports for easier use on the front.
# VATRate
Create a new entity or several to store the data of the last report X, with all calculations.
- A route for the X report that calculates everything at the moment T and returns a better formatted JSON.
- A route for the Z report that retrieves the data stored in the previously mentioned entities.
**GET /pos/report-x/vat-rates/{{entity}}**
**PARAMS :**
- fiscalDate (date Y-m-d)
- startDate (date Y-m-d)
- endDate (date Y-m-d)
- user (int)
- bankAcount (int)
```json
{
"fiscal_date": "2018-03-19",
"start_date": "2018-10-12T00:15:07+02:00",
"end_date": "2018-10-20T22:45:57+02:00",
"bank_account": {
"id": 1
},
"user": {
"id" : 1
},
"totals":{
"gross": {
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements" :[
{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":40.00
}]
},
"net": {
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements" :[{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":40.00
}]
},
"discount": {
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements" :[{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":40.00
}]
},
"meal_voucher": {
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements" :[{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":40.00
}]
}
},
"destinations":[
{
"label":"onsite",
"totals":{
"gross":{
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements":[
{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":80
}
]
},
"net": {
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements":[
{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":80
}
]
},
"discount": {
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements":[
{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":80
}
]
}
"meal_voucher": {
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements":[
{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":80
}
]
}
}
},
{
"label":"takeaway",
"totals":{
"gross":{
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements":[
{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":80
}
]
},
"net": {
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements":[
{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":80
}
]
},
"discount": {
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements":[
{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":80
}
]
}
"meal_voucher": {
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00,
"vat_elements":[
{
"vat_rate":5.5,
"label":"5,5%",
"total_excluding_taxes":37.91,
"total_vat":2.09,
"total_including_taxes":40.00
},
{
"vat_rate":20,
"label":"20%",
"total_excluding_taxes":100,
"total_vat":20,
"total_including_taxes":80
}
]
}
}
}
]
}
```
* For more clarity we will only process the reportX for the moment, the Z will be a reportX saved in the database (with modifications maybe...)
* The above object is built from several different roads:
- /pos/reports/report_x/vat_rates/{{{entity}}
```json
{
"account_id": null,
"team_member_id": null,
"rates": [
{
"uuid": null,
"type_label": "gross",
"destination_label": "ONSITE",
"rate_vat": 5.5,
"total_ttc": 40,
"total_vat": 2.0900000000000034,
"total_ht": 37.909999999999997
},
{
"uuid": null,
"type_label": "gross",
"destination_label": "ONSITE",
"rate_vat": 10,
"total_ttc": 23,
"total_vat": 2.0799999999999996,
"total_ht": 20.920000000000002
},
{
"uuid": null,
"type_label": "net",
"destination_label": "ONSITE",
"rate_vat": 5.5,
"total_ttc": 40,
"total_vat": 2.0900000000000034,
"total_ht": 37.909999999999997
},
{
"uuid": null,
"type_label": "net",
"destination_label": "ONSITE",
"rate_vat": 10,
"total_ttc": 23,
"total_vat": 2.0799999999999996,
"total_ht": 20.920000000000002
}
]
}
```
This data comes from the "ReportRateManager::getReportXRate" function which recovers the raw data with the `InvoiceDetRepository::getReportXData` functions and applies after a series of business calculations to build the above table.
The call to `InvoiceDetRepository::getReportXDiscount` is useless.
Business calculations to organize data by type (gross/net/discount/meal_coucher), vat and destination are done with the functions `ReportRateManager::getReportXRateByType` (for gross/discount/meal_voucher) and `ReportRateManager::getReportXRateNet` (for net).
Other sub-functions are called but we will stop here.
It is necessary to study well what each function does to deduce the business rules to be applied on the raw data and then write a script that allows to do the same thing but structuring according to the result we are trying to have.
- /pos/reports/report_z/discounts/vat_rates/{{{entity}}
This route calls `ReportRateDiscountController::getReportZRateDiscountAction` -> `ReportRateDiscountManager::getReportRateDiscount`. This function retrieves the raw data and builds an output as follows:
```json
{
"fiscal_date": "2018-11-15",
"start_date": "2018-11-15 05:00:00",
"end_date": "2018-11-15 10:31:25",
"account_id": 1,
"team_member_id": 1,
"destinations": [
{
"destination_label": "ONSITE",
"rate_vat": 10,
"total_ttc": 19.5,
"total_vat": 1.77272727,
"total_ht": 17.72727273
},
{
"destination_label": "ONSITE",
"rate_vat": 66,
"total_ttc": 25.5,
"total_vat": 9.77272727,
"total_ht": 78.72727273
}
]
}
```
The raw data used comes from the function `ReportRateDiscountRepository::getReportRateDiscountData`.
- /pos/reports/report_z/meal_vouchers/vat_rates/{{{entity}}
This route calls `ReportRateMealVoucherController::getReportZRateMealVoucherAction` -> `ReportRateMealVoucherManager::getReportZRateMealVoucher`. This function retrieves the raw data and builds an output as follows:
```json
{
"fiscal_date": "2018-11-15",
"start_date": "2018-11-15 05:00:00",
"end_date": "2018-11-15 10:31:25",
"account_id": 1,
"team_member_id": 1,
"destinations": [
{
"uuid": null,
"destination_label": "ONSITE",
"rate_vat": 10,
"total_ttc": 77.01,
"total_vat": 7.00090906,
"total_ht": 70.00909094000001
},
{
"uuid": null,
"destination_label": "ONSITE",
"rate_vat": 0,
"total_ttc": 0,
"total_vat": 0,
"total_ht": 0
}
]
}
```
The raw data used comes from the function `ReportRateMealVoucherRepository::getReportZRateMealVoucher`
# Interventions
In the same way as VATRates, we will create:
- a new entity or several entities to store the data of the last intervention report,
- a route for the X report that calculates everything at the moment T and returns a better formatted JSON,
- a route for the Z report that retrieves the data stored in the previously mentioned entities.
The new route will allow the data from the intervention reports to be retrieved in a format that is better adapted to the front and does not require additional calculations.
*New interfaces*:
**GET /pos/report-x/interventions/{{entity}}**
**GET /pos/report-z/interventions/{{entity}}**
**PARAMS :**
- fiscalDate (date Y-m-d)
- startDate (date Y-m-d)
- endDate (date Y-m-d)
- user (int)
- bankAcount (int)
*Output :*
```json
{
"fiscal_date": "2018-11-15",
"start_date": "2018-11-15 05:00:00",
"end_date": "2018-11-15 10:31:25",
"bank_account": {
"id": 1
},
"user": {
"id": 1
},
"interventions": {
"requests": {
"total_nb_requested": 4,
"total_nb_order_requested": 4,
"intervention_elements": [{
"total_nb_requested": 3,
"total_nb_order_requested": 3,
"type": "CANCEL_INVOICE",
"users": [{
"id": 1,
"firstname": "Caissier_1",
"lastname": "Jean",
"nb_requested": 2,
"nb_order_requested": 2
},
{
"id": 2,
"firstname": "Caissier_2",
"lastname": "Jean-Claude",
"nb_requested": 1,
"nb_order_requested": 1
}
]
},
{
"total_nb_requested": 1,
"total_nb_order_requested": 1,
"type": "VALIDATE_DISCOUNT",
"users": [{
"id": 3,
"firstname": "Caissier_3",
"lastname": "Jean-Michel",
"nb_requested": 1,
"nb_order_requested": 1
}]
}
]
},
"validations": {
"total_nb_validated": 4,
"total_nb_order_validated": 4,
"element_intervention": [{
"total_nb_validated": 3,
"total_nb_order_validated": 3,
"type": "CANCEL_INVOICE",
"users": [{
"id": 1,
"firstname": "Manager_1",
"lastname": "Paul",
"nb_validated": 2,
"nb_order_validated": 2
},
{
"id": 2,
"firstname": "Manager_2",
"lastname": "Michel",
"nb_validated": 1,
"nb_order_validated": 1
}
]
},
{
"total_nb_validated": 1,
"total_nb_order_validated": 1,
"type": "VALIDATE_DISCOUNT",
"users": [{
"id": 3,
"firstname": "Manager_3",
"lastname": "Pierre",
"nb_validated": 1,
"nb_order_validated": 1
}]
}
]
}
}
}
```
*Existing*:
The object below is currently being built from the interface:
GET /pos/reports/report_x/report_x/interventions/{{{entity}}} whose output is as follows:
```json
"account_id": null,
"team_member_id": null,
"interventions": [
{
"interventions_user": [
{
"uuid": null,
"user": {
"id": 2,
"lastname": "SUPPORT",
"firstname": "WYND"
},
"nb_requested": 1,
"nb_order_requested": 1,
"nb_validated": 1,
"nb_order_validated": 1
}
],
"type": "ERASE_PRODUCT"
}
]
}
```
For the X report the data comes only from the function `ReportIntervention::getReportXIntervention` which recovers the raw data (interventions) via the function `InterventionRepository::getReportInterventionData`. These data represent the interventions by user (id, lastname and firstname) whether they are requests and/or validations.
This data is then used to perform calculations to recover by order and by USER the interventions (requests and validations) by type (deletion of a product, deletion of a payment, cancellation of an order... ) and for each type the quantity of requests and the quantity of validations[NB: A request and validation of an intervention type on an order can be made by the same user -> case of a manager for example].
From the raw data provided by `InterventionRepository::getReportInterventionData` we will build the new output displaying the interventions by requests and validations.
# Product
The goal is to create new routes that allow report data to be retrieved for divisions and products in a format that is better adapted to the front and that does not require additional calculations.
**GET /pos/report-x/report-x/divisions/{{{entity}}** -> a route to retrieve the divisions without the products (empty table) = no products
**GET /pos/report-x/divisions/{{division_id}}}/products/{{{entity}}** -> a route to retrieve product details (with pagination) = we ask for products for each division
Question: Can we put the entity just after report-x in the road as follows?
**GET /pos/report-x/{{{entity}}/divisions**
**PARAMS :**
- fiscalDate (date Y-m-d)
- startDate (date Y-m-d)
- endDate (date Y-m-d)
- user (int)
- bankAcount (int)
```json
{
"fiscal_date": "2018-03-19",
"start_date": "2018-10-12T00:15:07+02:00",
"end_date": "2018-10-20T22:45:57+02:00",
"bank_account": {
"id": 1
},
"user": {
"id": 1
},
"report": {
"id": 1
},
"total_quantity_divisions": 14,
"total_quantity_percent_divisions": 100,
"total_amount_divisions": 57.09,
"total_amount_percent_divisions": 100,
"total_discount_divisions": 20,
"divisions": [{
"division": {
"id": 1,
"uuid": "3367cd30-8c74-4ec6-bae5-b9ae090a254f",
"label": "Fast food"
},
"total_quantity": 7,
"total_quantity_percent": 50,
"total_amount": 31,
"total_percent": 54.30,
"total_discount": 0,
"products": [{
"id": "1",
"uuid": "5c62f574-2936-4ed9-9f8c-918c80c1e668",
"product": {
"id": 9,
"uuid": "830825e1-1ef6-11e9-8796-0242ac120006",
"label": "Triple big mac"
},
"default_label": "Triple big mac",
"quantity": 3,
"quantity_percent": 42.85,
"amount": 15,
"amount_percent": 48.38,
"discount": 0
},
{
"id": "2",
"uuid": "acc58383-2ca3-48a0-8b35-ca2f3e12e73d",
"product": {
"id": 5,
"uuid": "b116691a-2608-41c4-9d52-3d079dd326ff",
"label": "Wrap"
},
"default_label": "Wrap",
"quantity": 4,
"quantity_percent": 57.14,
"amount": 16,
"amount_percent": 51.61,
"discount": 0
}
]
},
{
"division": {
"id": 2,
"uuid": "79ad1e96-dffa-47d4-afe4-8a9a89cd137e",
"label": "Alimentaire"
},
"total_quantity": 6,
"total_quantity_percent": 42.85,
"total_amount": 18.40,
"total_percent": 32.22,
"total_discount": 20,
"products": [{
"id": "1",
"uuid": "5c62f574-2936-4ed9-9f8c-918c80c1e668",
"product": {
"id": 23,
"uuid": "830825e1-1ef6-11e9-8796-0242ac120006",
"label": "Jus de tomate"
},
"default_label": "Jus de tomate",
"quantity": 4,
"quantity_percent": 66.66,
"amount": 12,
"amount_percent": 65.21,
"discount": 20
},
{
"id": "2",
"uuid": "acc58383-2ca3-48a0-8b35-ca2f3e12e73d",
"product": {
"id": 9,
"uuid": "79ad1e96-dffa-47d4-afe4-8a9a89cd137e",
"label": "Coca cola"
},
"default_label": "Coca cola",
"quantity": 2,
"quantity_percent": 33.33,
"amount": 6.4,
"amount_percent": 34.78,
"discount": 0
}
]
},
{
"division": {
"id": 3,
"uuid": "3367cd30-8c74-4ec6-bae5-b9ae090a254f",
"label": "Division inconnue"
},
"total_quantity": 1,
"total_quantity_percent": 7.14,
"total_amount": 7.69,
"total_percent": 13.46,
"total_discount": 0,
"products": [{
"id": "1",
"uuid": "5c62f574-2936-4ed9-9f8c-918c80c1e668",
"product": {
"id": 6,
"uuid": "830825e1-1ef6-11e9-8796-0242ac120006",
"label": "Colgate"
},
"default_label": "Colgate",
"quantity": 1,
"quantity_percent": 7.14,
"amount": 7.69,
"amount_percent": 13.46,
"discount": 0
}]
}
]
}
```
The above object is built from the interface:
**/pos/reports/reports/report_x/products/{entity_id}**
which allows to recover the products of a report x
```json
"report_id": null,
"account_id": null,
"team_member_id": null,
"products": [
{
"division": {
"label": "Plats"
},
"product": {
"id": "2",
"default_label": "Pizza nordique"
},
"uuid": null,
"division_label": "Plats",
"sub_division_label": null,
"product_label": "Pizza nordique",
"product_id": 2,
"quantity": 1,
"amount": 15,
"total_discount": null,
"fk_report": null,
"quantity_percent": 25,
"amount_percent": 23.809523809524
},
{
"division": {
"label": "liquides"
},
"product": {
"id": "6",
"default_label": "Orangina"
},
"uuid": null,
"division_label": "liquides",
"sub_division_label": null,
"product_label": "Orangina",
"product_id": 6,
"quantity": 1,
"amount": 3,
"total_discount": null,
"fk_report": null,
"quantity_percent": 25,
"amount_percent": 4.7619047619048
},
{
"division": {
"label": "Plats"
},
"product": {
"id": "33",
"default_label": "Produit composé"
},
"uuid": null,
"division_label": "Plats",
"sub_division_label": null,
"product_label": "Produit composé",
"product_id": 33,
"quantity": 1,
"amount": 40,
"total_discount": null,
"fk_report": null,
"quantity_percent": 25,
"amount_percent": 63.492063492063
},
{
"division": {
"label": "Entrées"
},
"product": {
"id": "37",
"default_label": "Muesli Choco Croustillant Chocolat"
},
"uuid": null,
"division_label": "Entrées",
"sub_division_label": null,
"product_label": "Muesli Choco Croustillant Chocolat",
"product_id": 37,
"quantity": 1,
"amount": 5,
"total_discount": null,
"fk_report": null,
"quantity_percent": 25,
"amount_percent": 7.9365079365079
}
]
}
```
Only one function is used to retrieve the raw data needed to build the above object. Here are the calls of the successive functions:
`ReportProductController` -> `ReportProductManager::getReportXProduct` -> `ReportProductRepository::getReportXProductData`
**getReportXProductData** returns this table of initial data that we will use to build the new output

# Roadmap
**For each element, we must do all the following steps:**
1- Data model design including a validation meeting[1 d]
2- Implementation of the data model + Doc model[1.5 d]
3- Controller implementation (A first version v.0 with routes, parameters and which returns an empty report, just to have a rendering, then come back to enrich it as you go along with the calls of the manager's functions for validation, data preparation, and calculations...) + Doc entrypoint[1.5 d].
4- Manager implementation (A first version v.0 with functions that prepare the data and create an empty report then come back to enrich them with the repository function calls as they happen)[0.5 d]
5- Study the functions of the repository that retrieve the raw data that we will use (Input/output and check how to use its parameters to have reports for a day/period...) [2 d]
6- Create repositories from existing functions and modify them if necessary to adapt them... [1.5 d]
7-Use the repository in the manager and implement the algorithms for data calculation and consolidation. [2 d]
8- Unit tests[2 days]
**This must be preceded by a macro design to see the relationship between the different reports (example: global report + product report + intervention report +...)**
=> This is[12 days] per element, so[36 days] for all three (vat rates, intervention, products)
* In addition to this, the function `ReportManager::getFiscalDate` needs to be reviewed. It can be duplicated and adapted to use the new reports instead of the old ones, or it can be reviewed and optimized for the new system. [1 d]
* Include the generation of new Z reports in the closing command of the `CloseReportCommand` reports[1.5 d]
Total estimate: ~[38.5 d]