From cf8dd122cd60771431c3120d0674b6fb617fa262 Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Mon, 29 Apr 2024 17:40:54 +0200 Subject: [PATCH 01/13] feat(api): Create an entrypoint to detect incoherence --- backend/api/items.go | 49 ++++ backend/autogen/bar.gen.go | 365 ++++++++++++++++--------- backend/internal/db/database.go | 2 + backend/internal/db/mongo/item_misc.go | 154 +++++++++++ bar.openapi.yml | 61 +++++ frontend/src/lib/api/api.ts | 74 +++++ 6 files changed, 577 insertions(+), 128 deletions(-) diff --git a/backend/api/items.go b/backend/api/items.go index 80b8cee..8f3a2e8 100644 --- a/backend/api/items.go +++ b/backend/api/items.go @@ -299,3 +299,52 @@ func (s *Server) GetAllItems(c echo.Context, params autogen.GetAllItemsParams) e return nil } + +// (GET /items/incoherent) +func (s *Server) GetAllIncoherentItems(c echo.Context, params autogen.GetAllIncoherentItemsParams) error { + // Get account from cookie + account, err := MustGetAdmin(c) + if err != nil { + return nil + } + + count, err := s.DBackend.CountIncoherentItems(c.Request().Context()) + if err != nil { + logrus.Error(err) + return Error500(c) + } + + // Make sure the last page is not empty + dbpage, page, limit, maxPage := autogen.Pager(params.Page, params.Limit, &count) + + data, err := s.DBackend.GetIncoherentItems(c.Request().Context(), dbpage, limit) + if err != nil { + logrus.Error(err) + return Error500(c) + } + + + + var items []autogen.Item + + for _, item := range data { + rp := item.RealPrice(account.PriceRole) + item.DisplayPrice = &rp + + if account.HasPrivileges() { + rp := item.RealPrices() + item.DisplayPrices = &rp + } + + items = append(items, item.Item) + } + + autogen.GetAllIncoherentItems200JSONResponse{ + Items: items, + Page: page, + Limit: limit, + MaxPage: maxPage, + }.VisitGetAllIncoherentItemsResponse(c.Response()) + + return nil +} \ No newline at end of file diff --git a/backend/autogen/bar.gen.go b/backend/autogen/bar.gen.go index be27516..a49926d 100644 --- a/backend/autogen/bar.gen.go +++ b/backend/autogen/bar.gen.go @@ -887,6 +887,15 @@ type GetAllItemsParams struct { Fournisseur *Fournisseur `form:"fournisseur,omitempty" json:"fournisseur,omitempty" bson:"fournisseur"` } +// GetAllIncoherentItemsParams defines parameters for GetAllIncoherentItems. +type GetAllIncoherentItemsParams struct { + // Page Page number + Page *uint64 `form:"page,omitempty" json:"page,omitempty" bson:"page"` + + // Limit Number of items per page + Limit *uint64 `form:"limit,omitempty" json:"limit,omitempty" bson:"limit"` +} + // GetRefillsParams defines parameters for GetRefills. type GetRefillsParams struct { // Page Page number @@ -1232,6 +1241,9 @@ type ServerInterface interface { // (GET /items) GetAllItems(ctx echo.Context, params GetAllItemsParams) error + // (GET /items/incoherent) + GetAllIncoherentItems(ctx echo.Context, params GetAllIncoherentItemsParams) error + // (GET /logout) Logout(ctx echo.Context) error @@ -2933,6 +2945,33 @@ func (w *ServerInterfaceWrapper) GetAllItems(ctx echo.Context) error { return err } +// GetAllIncoherentItems converts echo context to params. +func (w *ServerInterfaceWrapper) GetAllIncoherentItems(ctx echo.Context) error { + var err error + + ctx.Set(Admin_authScopes, []string{}) + + // Parameter object where we will unmarshal all parameters from the context + var params GetAllIncoherentItemsParams + // ------------- Optional query parameter "page" ------------- + + err = runtime.BindQueryParameter("form", true, false, "page", ctx.QueryParams(), ¶ms.Page) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter page: %s", err)) + } + + // ------------- Optional query parameter "limit" ------------- + + err = runtime.BindQueryParameter("form", true, false, "limit", ctx.QueryParams(), ¶ms.Limit) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err)) + } + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.GetAllIncoherentItems(ctx, params) + return err +} + // Logout converts echo context to params. func (w *ServerInterfaceWrapper) Logout(ctx echo.Context) error { var err error @@ -3221,6 +3260,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.PATCH(baseURL+"/deleted/transactions/:transaction_id", wrapper.RestoreDeletedTransaction) router.POST(baseURL+"/import/accounts", wrapper.ImportAccounts) router.GET(baseURL+"/items", wrapper.GetAllItems) + router.GET(baseURL+"/items/incoherent", wrapper.GetAllIncoherentItems) router.GET(baseURL+"/logout", wrapper.Logout) router.GET(baseURL+"/refills", wrapper.GetRefills) router.GET(baseURL+"/restocks", wrapper.GetRestocks) @@ -7325,6 +7365,46 @@ func (response GetAllItems500JSONResponse) VisitGetAllItemsResponse(w http.Respo return json.NewEncoder(w).Encode(response) } +type GetAllIncoherentItemsRequestObject struct { + Params GetAllIncoherentItemsParams `bson:"params"` +} + +type GetAllIncoherentItemsResponseObject interface { + VisitGetAllIncoherentItemsResponse(w http.ResponseWriter) error +} + +type GetAllIncoherentItems200JSONResponse struct { + Items []Item `json:"items" bson:"items"` + Limit uint64 `json:"limit" bson:"limit"` + MaxPage uint64 `json:"max_page" bson:"max_page"` + Page uint64 `json:"page" bson:"page"` +} + +func (response GetAllIncoherentItems200JSONResponse) VisitGetAllIncoherentItemsResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type GetAllIncoherentItems403JSONResponse HTTPError + +func (response GetAllIncoherentItems403JSONResponse) VisitGetAllIncoherentItemsResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(403) + + return json.NewEncoder(w).Encode(response) +} + +type GetAllIncoherentItems500JSONResponse HTTPError + +func (response GetAllIncoherentItems500JSONResponse) VisitGetAllIncoherentItemsResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(500) + + return json.NewEncoder(w).Encode(response) +} + type LogoutRequestObject struct { } @@ -7912,6 +7992,9 @@ type StrictServerInterface interface { // (GET /items) GetAllItems(ctx context.Context, request GetAllItemsRequestObject) (GetAllItemsResponseObject, error) + // (GET /items/incoherent) + GetAllIncoherentItems(ctx context.Context, request GetAllIncoherentItemsRequestObject) (GetAllIncoherentItemsResponseObject, error) + // (GET /logout) Logout(ctx context.Context, request LogoutRequestObject) (LogoutResponseObject, error) @@ -9998,6 +10081,31 @@ func (sh *strictHandler) GetAllItems(ctx echo.Context, params GetAllItemsParams) return nil } +// GetAllIncoherentItems operation middleware +func (sh *strictHandler) GetAllIncoherentItems(ctx echo.Context, params GetAllIncoherentItemsParams) error { + var request GetAllIncoherentItemsRequestObject + + request.Params = params + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.GetAllIncoherentItems(ctx.Request().Context(), request.(GetAllIncoherentItemsRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetAllIncoherentItems") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(GetAllIncoherentItemsResponseObject); ok { + return validResponse.VisitGetAllIncoherentItemsResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + // Logout operation middleware func (sh *strictHandler) Logout(ctx echo.Context) error { var request LogoutRequestObject @@ -10178,134 +10286,135 @@ func (sh *strictHandler) GetTransactionsItems(ctx echo.Context, params GetTransa // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "z/8XAAD//zDDl3F3pAEA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/backend/internal/db/database.go b/backend/internal/db/database.go index 51071fc..34035d0 100644 --- a/backend/internal/db/database.go +++ b/backend/internal/db/database.go @@ -163,7 +163,9 @@ type DBackend interface { GetRefills(ctx context.Context, account string, page uint64, size uint64, startAt, endAt uint64) ([]*models.Refill, error) CountRefills(ctx context.Context, account string, startAt, endAt uint64) (uint64, error) GetItems(ctx context.Context, categoryID string, page, size uint64, state string, name string, fournisseur string) ([]*models.Item, error) + GetIncoherentItems(ctx context.Context, page, size uint64) ([]*models.Item, error) CountItems(ctx context.Context, categoryID string, state string, name string, fournisseur string) (uint64, error) + CountIncoherentItems(ctx context.Context) (uint64, error) GetAllRefills(ctx context.Context, page uint64, size uint64, startAt, endAt uint64) ([]*models.Refill, error) CountAllRefills(ctx context.Context, startAt, endAt uint64) (uint64, error) diff --git a/backend/internal/db/mongo/item_misc.go b/backend/internal/db/mongo/item_misc.go index fa61183..518f1ed 100644 --- a/backend/internal/db/mongo/item_misc.go +++ b/backend/internal/db/mongo/item_misc.go @@ -88,6 +88,86 @@ func (b *Backend) GetItems(ctx context.Context, categoryID string, page, size ui return items, nil } +func (b *Backend) GetIncoherentItems(ctx context.Context, page, size uint64) ([]*models.Item, error) { + ctx, cancel := b.TimeoutContext(ctx) + defer cancel() + + var items []*models.Item + + filter := bson.M{ + "$or": []bson.M{ + { + "$and": []bson.M{ + { + "deleted_at": bson.M{ + "$exists": false, + }, + }, + { + "amount_left": bson.M{ + "$gt": 0, + }, + }, + { + "state": bson.M{ + "$ne": "buyable", + }, + }, + { + "$or": []bson.M{ + {"display_prices.ceten": 0}, + {"display_prices.coutant": 0}, + {"display_prices.externe": 0}, + {"display_prices.menu": 0}, + {"display_prices.privilegies": 0}, + {"display_prices.staff_bar": 0}, + {"prices.ceten": 0}, + {"prices.coutant": 0}, + {"prices.externe": 0}, + {"prices.menu": 0}, + {"prices.privilegies": 0}, + {"prices.staff_bar": 0}, + }, + }, + }, + }, + { + "amount_left": bson.M{ + "$gt": 0, + }, + "state": bson.M{ + "$ne": "buyable", + }, + "$or": []bson.M{ + {"display_prices.ceten": 0}, + {"display_prices.coutant": 0}, + {"display_prices.externe": 0}, + {"display_prices.menu": 0}, + {"display_prices.privilegies": 0}, + {"display_prices.staff_bar": 0}, + {"prices.ceten": 0}, + {"prices.coutant": 0}, + {"prices.externe": 0}, + {"prices.menu": 0}, + {"prices.privilegies": 0}, + {"prices.staff_bar": 0}, + }, + }, + }, + } + + cursor, err := b.db.Collection(ItemsCollection).Find(ctx, filter, options.Find().SetSkip(int64(page*size)).SetLimit(int64(size))) + if err != nil { + return nil, err + } + + if err := cursor.All(ctx, &items); err != nil { + return nil, err + } + + return items, nil +} + func (b *Backend) CountItems(ctx context.Context, categoryID string, state string, name string, fournisseur string) (uint64, error) { ctx, cancel := b.TimeoutContext(ctx) defer cancel() @@ -156,3 +236,77 @@ func (b *Backend) CountItems(ctx context.Context, categoryID string, state strin return uint64(count), nil } + +func (b *Backend) CountIncoherentItems(ctx context.Context) (uint64, error) { + ctx, cancel := b.TimeoutContext(ctx) + defer cancel() + + filter := bson.M{ + "$or": []bson.M{ + { + "$and": []bson.M{ + { + "deleted_at": bson.M{ + "$exists": false, + }, + }, + { + "amount_left": bson.M{ + "$gt": 0, + }, + }, + { + "state": bson.M{ + "$ne": "buyable", + }, + }, + { + "$or": []bson.M{ + {"display_prices.ceten": 0}, + {"display_prices.coutant": 0}, + {"display_prices.externe": 0}, + {"display_prices.menu": 0}, + {"display_prices.privilegies": 0}, + {"display_prices.staff_bar": 0}, + {"prices.ceten": 0}, + {"prices.coutant": 0}, + {"prices.externe": 0}, + {"prices.menu": 0}, + {"prices.privilegies": 0}, + {"prices.staff_bar": 0}, + }, + }, + }, + }, + { + "amount_left": bson.M{ + "$gt": 0, + }, + "state": bson.M{ + "$ne": "buyable", + }, + "$or": []bson.M{ + {"display_prices.ceten": 0}, + {"display_prices.coutant": 0}, + {"display_prices.externe": 0}, + {"display_prices.menu": 0}, + {"display_prices.privilegies": 0}, + {"display_prices.staff_bar": 0}, + {"prices.ceten": 0}, + {"prices.coutant": 0}, + {"prices.externe": 0}, + {"prices.menu": 0}, + {"prices.privilegies": 0}, + {"prices.staff_bar": 0}, + }, + }, + }, + } + + count, err := b.db.Collection(ItemsCollection).CountDocuments(ctx, filter) + if err != nil { + return 0, err + } + + return uint64(count), nil +} \ No newline at end of file diff --git a/bar.openapi.yml b/bar.openapi.yml index 0fa4af3..5f6dc65 100644 --- a/bar.openapi.yml +++ b/bar.openapi.yml @@ -2442,6 +2442,67 @@ paths: - admin_auth: [] tags: - items + /items/incoherent: + get: + description: (admin) Get all incoherent items with pagination + operationId: getAllIncoherentItems + parameters: + - name: page + in: query + description: Page number + required: false + schema: + type: integer + format: uint64 + - name: limit + in: query + description: Number of items per page + required: false + schema: + type: integer + format: uint64 + responses: + "200": + description: "" + content: + application/json: + schema: + type: object + properties: + items: + type: array + items: + $ref: "#/components/schemas/Item" + page: + type: integer + format: uint64 + limit: + type: integer + format: uint64 + max_page: + type: integer + format: uint64 + required: + - items + - page + - limit + - max_page + "403": + description: "Forbidden" + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPError" + "500": + description: "Internal server error" + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPError" + security: + - admin_auth: [] + tags: + - items /categories/{category_id}/items: get: description: Get all items of a category diff --git a/frontend/src/lib/api/api.ts b/frontend/src/lib/api/api.ts index 2156800..8ab8a81 100644 --- a/frontend/src/lib/api/api.ts +++ b/frontend/src/lib/api/api.ts @@ -6825,6 +6825,47 @@ export class DeletedApi extends BaseAPI { */ export const ItemsApiAxiosParamCreator = function (configuration?: Configuration) { return { + /** + * (admin) Get all incoherent items with pagination + * @param {number} [page] Page number + * @param {number} [limit] Number of items per page + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getAllIncoherentItems: async (page?: number, limit?: number, options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/items/incoherent`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication admin_auth required + + if (page !== undefined) { + localVarQueryParameter['page'] = page; + } + + if (limit !== undefined) { + localVarQueryParameter['limit'] = limit; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * (admin) Get all items with filters and pagination * @param {number} [page] Page number @@ -7110,6 +7151,17 @@ export const ItemsApiAxiosParamCreator = function (configuration?: Configuration export const ItemsApiFp = function(configuration?: Configuration) { const localVarAxiosParamCreator = ItemsApiAxiosParamCreator(configuration) return { + /** + * (admin) Get all incoherent items with pagination + * @param {number} [page] Page number + * @param {number} [limit] Number of items per page + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getAllIncoherentItems(page?: number, limit?: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getAllIncoherentItems(page, limit, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * (admin) Get all items with filters and pagination * @param {number} [page] Page number @@ -7193,6 +7245,16 @@ export const ItemsApiFp = function(configuration?: Configuration) { export const ItemsApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { const localVarFp = ItemsApiFp(configuration) return { + /** + * (admin) Get all incoherent items with pagination + * @param {number} [page] Page number + * @param {number} [limit] Number of items per page + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getAllIncoherentItems(page?: number, limit?: number, options?: any): AxiosPromise { + return localVarFp.getAllIncoherentItems(page, limit, options).then((request) => request(axios, basePath)); + }, /** * (admin) Get all items with filters and pagination * @param {number} [page] Page number @@ -7270,6 +7332,18 @@ export const ItemsApiFactory = function (configuration?: Configuration, basePath * @extends {BaseAPI} */ export class ItemsApi extends BaseAPI { + /** + * (admin) Get all incoherent items with pagination + * @param {number} [page] Page number + * @param {number} [limit] Number of items per page + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ItemsApi + */ + public getAllIncoherentItems(page?: number, limit?: number, options?: AxiosRequestConfig) { + return ItemsApiFp(this.configuration).getAllIncoherentItems(page, limit, options).then((request) => request(this.axios, this.basePath)); + } + /** * (admin) Get all items with filters and pagination * @param {number} [page] Page number From 4df7fb58ded2a6c17d0d034868dac56222647a77 Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Mon, 29 Apr 2024 17:41:37 +0200 Subject: [PATCH 02/13] fix(front): Change incoherence page to use new entrypoint --- frontend/src/routes/panel/products/incoherants/+page.svelte | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/routes/panel/products/incoherants/+page.svelte b/frontend/src/routes/panel/products/incoherants/+page.svelte index e91deda..89e7dee 100644 --- a/frontend/src/routes/panel/products/incoherants/+page.svelte +++ b/frontend/src/routes/panel/products/incoherants/+page.svelte @@ -76,7 +76,7 @@ function reloadItems() { itemsApi() - .getAllItems(page, itemsPerPage, searchState, searchCategory, searchName, undefined, { + .getAllIncoherentItems(page, itemsPerPage, { withCredentials: true }) .then((res) => { @@ -84,7 +84,6 @@ page = res.data.page ?? 0; itemsPerPage = res.data.limit ?? 0; items = res.data.items ?? []; - items = items.filter(item => item.amount_left > 0 && item.state !== 'buyable'); }); } From 79fdc179945f4ad7c1ef22463998f29eb7ea0c83 Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Mon, 29 Apr 2024 17:45:29 +0200 Subject: [PATCH 03/13] fix(api): fix pager returned an extra page --- backend/autogen/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/autogen/utils.go b/backend/autogen/utils.go index b90314f..9f1f7b2 100644 --- a/backend/autogen/utils.go +++ b/backend/autogen/utils.go @@ -101,7 +101,7 @@ func Pager(page *uint64, limit *uint64, count *uint64) (dbPage uint64, pageOut u // We calculate the max page (0 if count is nil) if count != nil { maxPageFloat := float64(*count) / float64(limitOut) - maxPage = uint64(math.Ceil(maxPageFloat)) + maxPage = uint64(math.Floor(maxPageFloat)) } if pageOut > maxPage+1 { From 1eb353bbc1c40a83facc89eb641077797d9b49db Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Mon, 29 Apr 2024 18:02:36 +0200 Subject: [PATCH 04/13] feat(api): add filters for incoherent items --- backend/api/items.go | 17 +- backend/autogen/bar.gen.go | 288 ++++++++++++++----------- backend/internal/db/database.go | 4 +- backend/internal/db/mongo/item_misc.go | 90 +++++++- bar.openapi.yml | 21 +- frontend/src/lib/api/api.ts | 46 +++- 6 files changed, 319 insertions(+), 147 deletions(-) diff --git a/backend/api/items.go b/backend/api/items.go index 8f3a2e8..eac054c 100644 --- a/backend/api/items.go +++ b/backend/api/items.go @@ -308,7 +308,20 @@ func (s *Server) GetAllIncoherentItems(c echo.Context, params autogen.GetAllInco return nil } - count, err := s.DBackend.CountIncoherentItems(c.Request().Context()) + state := "" + categoryId := "" + name := "" + if params.State != nil { + state = string(*params.State) + } + if params.CategoryId != nil { + categoryId = params.CategoryId.String() + } + if params.Name != nil { + name = string(*params.Name) + } + + count, err := s.DBackend.CountIncoherentItems(c.Request().Context(), categoryId, state, name) if err != nil { logrus.Error(err) return Error500(c) @@ -317,7 +330,7 @@ func (s *Server) GetAllIncoherentItems(c echo.Context, params autogen.GetAllInco // Make sure the last page is not empty dbpage, page, limit, maxPage := autogen.Pager(params.Page, params.Limit, &count) - data, err := s.DBackend.GetIncoherentItems(c.Request().Context(), dbpage, limit) + data, err := s.DBackend.GetIncoherentItems(c.Request().Context(), dbpage, limit, categoryId, state, name) if err != nil { logrus.Error(err) return Error500(c) diff --git a/backend/autogen/bar.gen.go b/backend/autogen/bar.gen.go index a49926d..9c5ef07 100644 --- a/backend/autogen/bar.gen.go +++ b/backend/autogen/bar.gen.go @@ -894,6 +894,15 @@ type GetAllIncoherentItemsParams struct { // Limit Number of items per page Limit *uint64 `form:"limit,omitempty" json:"limit,omitempty" bson:"limit"` + + // State Filter by state + State *ItemState `form:"state,omitempty" json:"state,omitempty" bson:"state"` + + // CategoryId Filter by category + CategoryId *UUID `form:"category_id,omitempty" json:"category_id,omitempty" bson:"category_id"` + + // Name Filter by name + Name *string `form:"name,omitempty" json:"name,omitempty" bson:"name"` } // GetRefillsParams defines parameters for GetRefills. @@ -2967,6 +2976,27 @@ func (w *ServerInterfaceWrapper) GetAllIncoherentItems(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err)) } + // ------------- Optional query parameter "state" ------------- + + err = runtime.BindQueryParameter("form", true, false, "state", ctx.QueryParams(), ¶ms.State) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter state: %s", err)) + } + + // ------------- Optional query parameter "category_id" ------------- + + err = runtime.BindQueryParameter("form", true, false, "category_id", ctx.QueryParams(), ¶ms.CategoryId) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter category_id: %s", err)) + } + + // ------------- Optional query parameter "name" ------------- + + err = runtime.BindQueryParameter("form", true, false, "name", ctx.QueryParams(), ¶ms.Name) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter name: %s", err)) + } + // Invoke the callback with all the unmarshaled arguments err = w.Handler.GetAllIncoherentItems(ctx, params) return err @@ -10286,135 +10316,135 @@ func (sh *strictHandler) GetTransactionsItems(ctx echo.Context, params GetTransa // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "z/8XAAD//zDDl3F3pAEA", + "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", + "+fOX5/8LAAD//wrNSI3ApQEA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/backend/internal/db/database.go b/backend/internal/db/database.go index 34035d0..9e2458c 100644 --- a/backend/internal/db/database.go +++ b/backend/internal/db/database.go @@ -163,9 +163,9 @@ type DBackend interface { GetRefills(ctx context.Context, account string, page uint64, size uint64, startAt, endAt uint64) ([]*models.Refill, error) CountRefills(ctx context.Context, account string, startAt, endAt uint64) (uint64, error) GetItems(ctx context.Context, categoryID string, page, size uint64, state string, name string, fournisseur string) ([]*models.Item, error) - GetIncoherentItems(ctx context.Context, page, size uint64) ([]*models.Item, error) + GetIncoherentItems(ctx context.Context, page, size uint64, categoryID string, state string, name string) ([]*models.Item, error) CountItems(ctx context.Context, categoryID string, state string, name string, fournisseur string) (uint64, error) - CountIncoherentItems(ctx context.Context) (uint64, error) + CountIncoherentItems(ctx context.Context, categoryID string, state string, name string) (uint64, error) GetAllRefills(ctx context.Context, page uint64, size uint64, startAt, endAt uint64) ([]*models.Refill, error) CountAllRefills(ctx context.Context, startAt, endAt uint64) (uint64, error) diff --git a/backend/internal/db/mongo/item_misc.go b/backend/internal/db/mongo/item_misc.go index 518f1ed..83ff547 100644 --- a/backend/internal/db/mongo/item_misc.go +++ b/backend/internal/db/mongo/item_misc.go @@ -88,7 +88,7 @@ func (b *Backend) GetItems(ctx context.Context, categoryID string, page, size ui return items, nil } -func (b *Backend) GetIncoherentItems(ctx context.Context, page, size uint64) ([]*models.Item, error) { +func (b *Backend) GetIncoherentItems(ctx context.Context, page, size uint64, categoryID string, state string, name string) ([]*models.Item, error) { ctx, cancel := b.TimeoutContext(ctx) defer cancel() @@ -156,6 +156,50 @@ func (b *Backend) GetIncoherentItems(ctx context.Context, page, size uint64) ([] }, } + if state != "" { + filter["state"] = state + if state == string(autogen.ItemBuyable) { + // Get seconds since day start + t := time.Since(time.Now().Truncate(24 * time.Hour)).Seconds() + // available_from <= t <= available_until or (available_from == nil && available_until == nil) + filter["$and"] = []bson.M{ + { + "$or": []bson.M{ + { + "available_from": bson.M{ + "$lte": t, + }, + }, + { + "available_from": nil, + }, + }, + }, + { + "$or": []bson.M{ + { + "available_until": bson.M{ + "$gte": t, + }, + }, + { + "available_until": nil, + }, + }, + }, + } + } + } + if categoryID != "" { + filter["category_id"] = uuid.MustParse(categoryID) + } + if name != "" { + filter["name"] = bson.M{ + "$regex": name, + "$options": "i", + } + } + cursor, err := b.db.Collection(ItemsCollection).Find(ctx, filter, options.Find().SetSkip(int64(page*size)).SetLimit(int64(size))) if err != nil { return nil, err @@ -237,7 +281,7 @@ func (b *Backend) CountItems(ctx context.Context, categoryID string, state strin return uint64(count), nil } -func (b *Backend) CountIncoherentItems(ctx context.Context) (uint64, error) { +func (b *Backend) CountIncoherentItems(ctx context.Context, categoryID string, state string, name string) (uint64, error) { ctx, cancel := b.TimeoutContext(ctx) defer cancel() @@ -303,6 +347,48 @@ func (b *Backend) CountIncoherentItems(ctx context.Context) (uint64, error) { }, } + if state != "" { + filter["state"] = state + if state == string(autogen.ItemBuyable) { + t := time.Since(time.Now().Truncate(24 * time.Hour)).Seconds() + filter["$and"] = []bson.M{ + { + "$or": []bson.M{ + { + "available_from": bson.M{ + "$lte": t, + }, + }, + { + "available_from": nil, + }, + }, + }, + { + "$or": []bson.M{ + { + "available_until": bson.M{ + "$gte": t, + }, + }, + { + "available_until": nil, + }, + }, + }, + } + } + } + if categoryID != "" { + filter["category_id"] = uuid.MustParse(categoryID) + } + if name != "" { + filter["name"] = bson.M{ + "$regex": name, + "$options": "i", + } + } + count, err := b.db.Collection(ItemsCollection).CountDocuments(ctx, filter) if err != nil { return 0, err diff --git a/bar.openapi.yml b/bar.openapi.yml index 5f6dc65..25fcd1f 100644 --- a/bar.openapi.yml +++ b/bar.openapi.yml @@ -2444,7 +2444,7 @@ paths: - items /items/incoherent: get: - description: (admin) Get all incoherent items with pagination + description: (admin) Get all incoherent items with filters and pagination operationId: getAllIncoherentItems parameters: - name: page @@ -2461,6 +2461,25 @@ paths: schema: type: integer format: uint64 + - name: state + in: query + description: Filter by state + required: false + schema: + type: string + $ref: "#/components/schemas/ItemState" + - name: category_id + in: query + description: Filter by category + required: false + schema: + $ref: "#/components/schemas/UUID" + - name: name + in: query + description: Filter by name + required: false + schema: + type: string responses: "200": description: "" diff --git a/frontend/src/lib/api/api.ts b/frontend/src/lib/api/api.ts index 8ab8a81..1646f21 100644 --- a/frontend/src/lib/api/api.ts +++ b/frontend/src/lib/api/api.ts @@ -6826,13 +6826,16 @@ export class DeletedApi extends BaseAPI { export const ItemsApiAxiosParamCreator = function (configuration?: Configuration) { return { /** - * (admin) Get all incoherent items with pagination + * (admin) Get all incoherent items with filters and pagination * @param {number} [page] Page number * @param {number} [limit] Number of items per page + * @param {ItemState} [state] Filter by state + * @param {string} [categoryId] Filter by category + * @param {string} [name] Filter by name * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAllIncoherentItems: async (page?: number, limit?: number, options: AxiosRequestConfig = {}): Promise => { + getAllIncoherentItems: async (page?: number, limit?: number, state?: ItemState, categoryId?: string, name?: string, options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/items/incoherent`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -6855,6 +6858,18 @@ export const ItemsApiAxiosParamCreator = function (configuration?: Configuration localVarQueryParameter['limit'] = limit; } + if (state !== undefined) { + localVarQueryParameter['state'] = state; + } + + if (categoryId !== undefined) { + localVarQueryParameter['category_id'] = categoryId; + } + + if (name !== undefined) { + localVarQueryParameter['name'] = name; + } + setSearchParams(localVarUrlObj, localVarQueryParameter); @@ -7152,14 +7167,17 @@ export const ItemsApiFp = function(configuration?: Configuration) { const localVarAxiosParamCreator = ItemsApiAxiosParamCreator(configuration) return { /** - * (admin) Get all incoherent items with pagination + * (admin) Get all incoherent items with filters and pagination * @param {number} [page] Page number * @param {number} [limit] Number of items per page + * @param {ItemState} [state] Filter by state + * @param {string} [categoryId] Filter by category + * @param {string} [name] Filter by name * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getAllIncoherentItems(page?: number, limit?: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getAllIncoherentItems(page, limit, options); + async getAllIncoherentItems(page?: number, limit?: number, state?: ItemState, categoryId?: string, name?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getAllIncoherentItems(page, limit, state, categoryId, name, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -7246,14 +7264,17 @@ export const ItemsApiFactory = function (configuration?: Configuration, basePath const localVarFp = ItemsApiFp(configuration) return { /** - * (admin) Get all incoherent items with pagination + * (admin) Get all incoherent items with filters and pagination * @param {number} [page] Page number * @param {number} [limit] Number of items per page + * @param {ItemState} [state] Filter by state + * @param {string} [categoryId] Filter by category + * @param {string} [name] Filter by name * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getAllIncoherentItems(page?: number, limit?: number, options?: any): AxiosPromise { - return localVarFp.getAllIncoherentItems(page, limit, options).then((request) => request(axios, basePath)); + getAllIncoherentItems(page?: number, limit?: number, state?: ItemState, categoryId?: string, name?: string, options?: any): AxiosPromise { + return localVarFp.getAllIncoherentItems(page, limit, state, categoryId, name, options).then((request) => request(axios, basePath)); }, /** * (admin) Get all items with filters and pagination @@ -7333,15 +7354,18 @@ export const ItemsApiFactory = function (configuration?: Configuration, basePath */ export class ItemsApi extends BaseAPI { /** - * (admin) Get all incoherent items with pagination + * (admin) Get all incoherent items with filters and pagination * @param {number} [page] Page number * @param {number} [limit] Number of items per page + * @param {ItemState} [state] Filter by state + * @param {string} [categoryId] Filter by category + * @param {string} [name] Filter by name * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof ItemsApi */ - public getAllIncoherentItems(page?: number, limit?: number, options?: AxiosRequestConfig) { - return ItemsApiFp(this.configuration).getAllIncoherentItems(page, limit, options).then((request) => request(this.axios, this.basePath)); + public getAllIncoherentItems(page?: number, limit?: number, state?: ItemState, categoryId?: string, name?: string, options?: AxiosRequestConfig) { + return ItemsApiFp(this.configuration).getAllIncoherentItems(page, limit, state, categoryId, name, options).then((request) => request(this.axios, this.basePath)); } /** From c6fd5d31a6eac3675be1e0f0db08c8268cb197f1 Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Mon, 29 Apr 2024 18:03:10 +0200 Subject: [PATCH 05/13] feat(front): add filters on incoherent page --- frontend/src/routes/panel/products/incoherants/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/panel/products/incoherants/+page.svelte b/frontend/src/routes/panel/products/incoherants/+page.svelte index 89e7dee..3bd63e9 100644 --- a/frontend/src/routes/panel/products/incoherants/+page.svelte +++ b/frontend/src/routes/panel/products/incoherants/+page.svelte @@ -76,7 +76,7 @@ function reloadItems() { itemsApi() - .getAllIncoherentItems(page, itemsPerPage, { + .getAllIncoherentItems(page, itemsPerPage, searchState, searchCategory, searchName, { withCredentials: true }) .then((res) => { From d0befd3ce1b117ee0c4143c8d5009ca7c0cbf632 Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Mon, 29 Apr 2024 18:03:34 +0200 Subject: [PATCH 06/13] fix(front): change RestockType to Fournisseur --- frontend/src/routes/panel/products/fournisseur/+page.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/routes/panel/products/fournisseur/+page.svelte b/frontend/src/routes/panel/products/fournisseur/+page.svelte index 1ca0f20..5eb2057 100644 --- a/frontend/src/routes/panel/products/fournisseur/+page.svelte +++ b/frontend/src/routes/panel/products/fournisseur/+page.svelte @@ -6,7 +6,7 @@ ItemPrices, UpdateItem, AccountPriceRole, - RestockType + Fournisseur } from '$lib/api'; import ConfirmationPopup from '$lib/components/confirmationPopup.svelte'; import { api } from '$lib/config/config'; @@ -61,7 +61,7 @@ let rebounceTimeout: number | null = null; - let searchFournisseur: RestockType | undefined = undefined; + let searchFournisseur: Fournisseur | undefined = undefined; let searchCategory: string | undefined = undefined; let searchName: string | undefined = undefined; From 4f2e4eb66255c60a1847470e7e45e281d0aff659 Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Sat, 4 May 2024 16:04:38 +0200 Subject: [PATCH 07/13] fix(api): modify filter to get item with price 0 and buyable and don't get deleted item --- backend/internal/db/mongo/item_misc.go | 115 +++++++------------------ 1 file changed, 33 insertions(+), 82 deletions(-) diff --git a/backend/internal/db/mongo/item_misc.go b/backend/internal/db/mongo/item_misc.go index 83ff547..2f86d7c 100644 --- a/backend/internal/db/mongo/item_misc.go +++ b/backend/internal/db/mongo/item_misc.go @@ -95,50 +95,26 @@ func (b *Backend) GetIncoherentItems(ctx context.Context, page, size uint64, cat var items []*models.Item filter := bson.M{ - "$or": []bson.M{ + "$and": []bson.M{ { - "$and": []bson.M{ - { - "deleted_at": bson.M{ - "$exists": false, - }, - }, - { - "amount_left": bson.M{ - "$gt": 0, - }, - }, - { - "state": bson.M{ - "$ne": "buyable", - }, - }, - { - "$or": []bson.M{ - {"display_prices.ceten": 0}, - {"display_prices.coutant": 0}, - {"display_prices.externe": 0}, - {"display_prices.menu": 0}, - {"display_prices.privilegies": 0}, - {"display_prices.staff_bar": 0}, - {"prices.ceten": 0}, - {"prices.coutant": 0}, - {"prices.externe": 0}, - {"prices.menu": 0}, - {"prices.privilegies": 0}, - {"prices.staff_bar": 0}, - }, - }, - }, + "deleted_at": nil, }, { - "amount_left": bson.M{ - "$gt": 0, - }, - "state": bson.M{ - "$ne": "buyable", - }, "$or": []bson.M{ + { + "$and": []bson.M{ + { + "amount_left": bson.M{ + "$gt": 0, + }, + }, + { + "state": bson.M{ + "$ne": "buyable", + }, + }, + }, + }, {"display_prices.ceten": 0}, {"display_prices.coutant": 0}, {"display_prices.externe": 0}, @@ -155,7 +131,6 @@ func (b *Backend) GetIncoherentItems(ctx context.Context, page, size uint64, cat }, }, } - if state != "" { filter["state"] = state if state == string(autogen.ItemBuyable) { @@ -286,50 +261,26 @@ func (b *Backend) CountIncoherentItems(ctx context.Context, categoryID string, s defer cancel() filter := bson.M{ - "$or": []bson.M{ + "$and": []bson.M{ { - "$and": []bson.M{ - { - "deleted_at": bson.M{ - "$exists": false, - }, - }, - { - "amount_left": bson.M{ - "$gt": 0, - }, - }, - { - "state": bson.M{ - "$ne": "buyable", - }, - }, - { - "$or": []bson.M{ - {"display_prices.ceten": 0}, - {"display_prices.coutant": 0}, - {"display_prices.externe": 0}, - {"display_prices.menu": 0}, - {"display_prices.privilegies": 0}, - {"display_prices.staff_bar": 0}, - {"prices.ceten": 0}, - {"prices.coutant": 0}, - {"prices.externe": 0}, - {"prices.menu": 0}, - {"prices.privilegies": 0}, - {"prices.staff_bar": 0}, - }, - }, - }, + "deleted_at": nil, }, { - "amount_left": bson.M{ - "$gt": 0, - }, - "state": bson.M{ - "$ne": "buyable", - }, "$or": []bson.M{ + { + "$and": []bson.M{ + { + "amount_left": bson.M{ + "$gt": 0, + }, + }, + { + "state": bson.M{ + "$ne": "buyable", + }, + }, + }, + }, {"display_prices.ceten": 0}, {"display_prices.coutant": 0}, {"display_prices.externe": 0}, @@ -395,4 +346,4 @@ func (b *Backend) CountIncoherentItems(ctx context.Context, categoryID string, s } return uint64(count), nil -} \ No newline at end of file +} From c18faa10f256c54ccd10cf38771bb715affc4dae Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Sat, 4 May 2024 17:35:41 +0200 Subject: [PATCH 08/13] fix(api): pager needs to give one less page --- backend/autogen/utils.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/autogen/utils.go b/backend/autogen/utils.go index 9f1f7b2..e56ffab 100644 --- a/backend/autogen/utils.go +++ b/backend/autogen/utils.go @@ -3,6 +3,7 @@ package autogen import ( "math" "time" + "github.com/sirupsen/logrus" ) func OptionalString(s string) *string { @@ -101,7 +102,7 @@ func Pager(page *uint64, limit *uint64, count *uint64) (dbPage uint64, pageOut u // We calculate the max page (0 if count is nil) if count != nil { maxPageFloat := float64(*count) / float64(limitOut) - maxPage = uint64(math.Floor(maxPageFloat)) + maxPage = uint64(math.Ceil(maxPageFloat) - 1) } if pageOut > maxPage+1 { From 91a8e8c0de994b7968dc9fb57f25f2c2e21fe70e Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Sat, 4 May 2024 17:36:49 +0200 Subject: [PATCH 09/13] fix(api): forgot to remove logrus import --- backend/autogen/utils.go | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/autogen/utils.go b/backend/autogen/utils.go index e56ffab..3af9a18 100644 --- a/backend/autogen/utils.go +++ b/backend/autogen/utils.go @@ -3,7 +3,6 @@ package autogen import ( "math" "time" - "github.com/sirupsen/logrus" ) func OptionalString(s string) *string { From eccfd26ffe291338ecec4cd53db092375b5dc33f Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Mon, 3 Jun 2024 17:16:16 +0200 Subject: [PATCH 10/13] fix(api): Remove displayprice fields from GetIncoherentItems query --- backend/internal/db/mongo/item_misc.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/backend/internal/db/mongo/item_misc.go b/backend/internal/db/mongo/item_misc.go index 2f86d7c..9b3c230 100644 --- a/backend/internal/db/mongo/item_misc.go +++ b/backend/internal/db/mongo/item_misc.go @@ -115,12 +115,6 @@ func (b *Backend) GetIncoherentItems(ctx context.Context, page, size uint64, cat }, }, }, - {"display_prices.ceten": 0}, - {"display_prices.coutant": 0}, - {"display_prices.externe": 0}, - {"display_prices.menu": 0}, - {"display_prices.privilegies": 0}, - {"display_prices.staff_bar": 0}, {"prices.ceten": 0}, {"prices.coutant": 0}, {"prices.externe": 0}, From cb21df62ef4d61a1bccac284d178d621f7ae2b67 Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Mon, 3 Jun 2024 17:20:26 +0200 Subject: [PATCH 11/13] fix(api): remove displayprice from CountIncoherentItems too --- backend/internal/db/mongo/item_misc.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/backend/internal/db/mongo/item_misc.go b/backend/internal/db/mongo/item_misc.go index 9b3c230..24099e4 100644 --- a/backend/internal/db/mongo/item_misc.go +++ b/backend/internal/db/mongo/item_misc.go @@ -275,12 +275,6 @@ func (b *Backend) CountIncoherentItems(ctx context.Context, categoryID string, s }, }, }, - {"display_prices.ceten": 0}, - {"display_prices.coutant": 0}, - {"display_prices.externe": 0}, - {"display_prices.menu": 0}, - {"display_prices.privilegies": 0}, - {"display_prices.staff_bar": 0}, {"prices.ceten": 0}, {"prices.coutant": 0}, {"prices.externe": 0}, From 3c95c99f84f439acfe3c283aab90d4bf44fd88e7 Mon Sep 17 00:00:00 2001 From: JULLIEN Baptiste Date: Tue, 4 Jun 2024 12:58:25 +0200 Subject: [PATCH 12/13] fix(api): roleback on pager to fix it in another pr --- backend/autogen/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/autogen/utils.go b/backend/autogen/utils.go index 3af9a18..9f1f7b2 100644 --- a/backend/autogen/utils.go +++ b/backend/autogen/utils.go @@ -101,7 +101,7 @@ func Pager(page *uint64, limit *uint64, count *uint64) (dbPage uint64, pageOut u // We calculate the max page (0 if count is nil) if count != nil { maxPageFloat := float64(*count) / float64(limitOut) - maxPage = uint64(math.Ceil(maxPageFloat) - 1) + maxPage = uint64(math.Floor(maxPageFloat)) } if pageOut > maxPage+1 { From e6a27a3a9420e941ef88246a84533c958f35c0b1 Mon Sep 17 00:00:00 2001 From: Aristide Urli Date: Tue, 4 Jun 2024 15:29:31 +0200 Subject: [PATCH 13/13] revert(api): revert backend/autogen/utils.go before pager fix attempt Refs: 2b793b9 --- backend/autogen/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/autogen/utils.go b/backend/autogen/utils.go index 9f1f7b2..b90314f 100644 --- a/backend/autogen/utils.go +++ b/backend/autogen/utils.go @@ -101,7 +101,7 @@ func Pager(page *uint64, limit *uint64, count *uint64) (dbPage uint64, pageOut u // We calculate the max page (0 if count is nil) if count != nil { maxPageFloat := float64(*count) / float64(limitOut) - maxPage = uint64(math.Floor(maxPageFloat)) + maxPage = uint64(math.Ceil(maxPageFloat)) } if pageOut > maxPage+1 {