diff --git a/.secrets.baseline b/.secrets.baseline index bfff0820..7ca734fa 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -175,15 +175,6 @@ "line_number": 1 } ], - "docker-compose-apisix.yml": [ - { - "type": "Secret Keyword", - "filename": "docker-compose-apisix.yml", - "hashed_secret": "965f383cb0ba71f9e9d33ae7eec9380590a4e9e3", - "is_verified": false, - "line_number": 43 - } - ], "docker-compose.yml": [ { "type": "Basic Auth Credentials", @@ -194,5 +185,5 @@ } ] }, - "generated_at": "2024-11-21T20:53:59Z" + "generated_at": "2024-12-05T14:34:37Z" } diff --git a/cart/templates/cart.html b/cart/templates/cart.html index 8e115284..3c03de8c 100644 --- a/cart/templates/cart.html +++ b/cart/templates/cart.html @@ -96,7 +96,9 @@ diff --git a/config/apisix/apisix.yaml b/config/apisix/apisix.yaml index 6ff2f32f..203deeda 100644 --- a/config/apisix/apisix.yaml +++ b/config/apisix/apisix.yaml @@ -27,6 +27,7 @@ routes: - "/auth/*" - "/static/*" - "/favicon.ico" + - "/checkout/*" - id: 2 name: "ue-default" desc: "Wildcard route for the rest of the system - authentication required" diff --git a/frontends/api/src/generated/v0/api.ts b/frontends/api/src/generated/v0/api.ts index 05250636..77b1e783 100644 --- a/frontends/api/src/generated/v0/api.ts +++ b/frontends/api/src/generated/v0/api.ts @@ -103,6 +103,100 @@ export interface BasketWithProduct { */ 'total_price': number; } +/** + * Serializer for companies. + * @export + * @interface Company + */ +export interface Company { + /** + * + * @type {number} + * @memberof Company + */ + 'id': number; + /** + * + * @type {string} + * @memberof Company + */ + 'name': string; +} +/** + * Serializer for discounts. + * @export + * @interface Discount + */ +export interface Discount { + /** + * + * @type {number} + * @memberof Discount + */ + 'id': number; + /** + * + * @type {string} + * @memberof Discount + */ + 'discount_code': string; + /** + * + * @type {string} + * @memberof Discount + */ + 'amount': string; + /** + * + * @type {PaymentTypeEnum} + * @memberof Discount + */ + 'payment_type'?: PaymentTypeEnum | null; + /** + * + * @type {number} + * @memberof Discount + */ + 'max_redemptions'?: number | null; + /** + * If set, this discount code will not be redeemable before this date. + * @type {string} + * @memberof Discount + */ + 'activation_date'?: string | null; + /** + * If set, this discount code will not be redeemable after this date. + * @type {string} + * @memberof Discount + */ + 'expiration_date'?: string | null; + /** + * + * @type {IntegratedSystem} + * @memberof Discount + */ + 'integrated_system': IntegratedSystem; + /** + * + * @type {Product} + * @memberof Discount + */ + 'product': Product; + /** + * + * @type {Array} + * @memberof Discount + */ + 'assigned_users': Array; + /** + * + * @type {Company} + * @memberof Discount + */ + 'company': Company; +} + + /** * Serializer for IntegratedSystem model. * @export @@ -202,6 +296,23 @@ export interface Line { */ 'product': Product; } +/** + * + * @export + * @enum {string} + */ + +export const NullEnumDescriptions = { + 'null': "", +} as const; + +export const NullEnum = { + Null: 'null' +} as const; + +export type NullEnum = typeof NullEnum[keyof typeof NullEnum]; + + /** * Serializer for order history. * @export @@ -451,6 +562,61 @@ export interface PatchedProductRequest { */ 'price'?: string; } +/** + * * `marketing` - marketing * `sales` - sales * `financial-assistance` - financial-assistance * `customer-support` - customer-support * `staff` - staff * `legacy` - legacy * `credit_card` - credit_card * `purchase_order` - purchase_order + * @export + * @enum {string} + */ + +export const PaymentTypeEnumDescriptions = { + 'marketing': "marketing", + 'sales': "sales", + 'financial-assistance': "financial-assistance", + 'customer-support': "customer-support", + 'staff': "staff", + 'legacy': "legacy", + 'credit_card': "credit_card", + 'purchase_order': "purchase_order", +} as const; + +export const PaymentTypeEnum = { + /** + * marketing + */ + Marketing: 'marketing', + /** + * sales + */ + Sales: 'sales', + /** + * financial-assistance + */ + FinancialAssistance: 'financial-assistance', + /** + * customer-support + */ + CustomerSupport: 'customer-support', + /** + * staff + */ + Staff: 'staff', + /** + * legacy + */ + Legacy: 'legacy', + /** + * credit_card + */ + CreditCard: 'credit_card', + /** + * purchase_order + */ + PurchaseOrder: 'purchase_order' +} as const; + +export type PaymentTypeEnum = typeof PaymentTypeEnum[keyof typeof PaymentTypeEnum]; + + /** * Serializer for Product model. * @export @@ -1834,6 +2000,39 @@ export const PaymentsApiAxiosParamCreator = function (configuration?: Configurat + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Returns or creates a basket for the current user and system. + * @param {string} system_slug + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + paymentsBasketsForSystemRetrieve: async (system_slug: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'system_slug' is not null or undefined + assertParamExists('paymentsBasketsForSystemRetrieve', 'system_slug', system_slug) + const localVarPath = `/api/v0/payments/baskets/for_system/{system_slug}/` + .replace(`{${"system_slug"}}`, encodeURIComponent(String(system_slug))); + // 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; + + + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -1911,6 +2110,35 @@ export const PaymentsApiAxiosParamCreator = function (configuration?: Configurat + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Create a discount. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + paymentsDiscountsCreate: async (options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/api/v0/payments/discounts/`; + // 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: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + setSearchParams(localVarUrlObj, localVarQueryParameter); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -2039,6 +2267,18 @@ export const PaymentsApiFp = function(configuration?: Configuration) { const operationBasePath = operationServerMap['PaymentsApi.paymentsBasketsCreateFromProductCreate']?.[index]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, + /** + * Returns or creates a basket for the current user and system. + * @param {string} system_slug + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async paymentsBasketsForSystemRetrieve(system_slug: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.paymentsBasketsForSystemRetrieve(system_slug, options); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['PaymentsApi.paymentsBasketsForSystemRetrieve']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); + }, /** * Retrives the current user\'s baskets, one per system. * @param {number} [integrated_system] @@ -2065,6 +2305,17 @@ export const PaymentsApiFp = function(configuration?: Configuration) { const operationBasePath = operationServerMap['PaymentsApi.paymentsBasketsRetrieve']?.[index]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); }, + /** + * Create a discount. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async paymentsDiscountsCreate(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.paymentsDiscountsCreate(options); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['PaymentsApi.paymentsDiscountsCreate']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); + }, /** * Retrives the current user\'s completed orders. * @param {number} [limit] Number of results to return per page. @@ -2127,6 +2378,15 @@ export const PaymentsApiFactory = function (configuration?: Configuration, baseP paymentsBasketsCreateFromProductCreate(requestParameters: PaymentsApiPaymentsBasketsCreateFromProductCreateRequest, options?: RawAxiosRequestConfig): AxiosPromise { return localVarFp.paymentsBasketsCreateFromProductCreate(requestParameters.sku, requestParameters.system_slug, options).then((request) => request(axios, basePath)); }, + /** + * Returns or creates a basket for the current user and system. + * @param {PaymentsApiPaymentsBasketsForSystemRetrieveRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + paymentsBasketsForSystemRetrieve(requestParameters: PaymentsApiPaymentsBasketsForSystemRetrieveRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.paymentsBasketsForSystemRetrieve(requestParameters.system_slug, options).then((request) => request(axios, basePath)); + }, /** * Retrives the current user\'s baskets, one per system. * @param {PaymentsApiPaymentsBasketsListRequest} requestParameters Request parameters. @@ -2145,6 +2405,14 @@ export const PaymentsApiFactory = function (configuration?: Configuration, baseP paymentsBasketsRetrieve(requestParameters: PaymentsApiPaymentsBasketsRetrieveRequest, options?: RawAxiosRequestConfig): AxiosPromise { return localVarFp.paymentsBasketsRetrieve(requestParameters.id, options).then((request) => request(axios, basePath)); }, + /** + * Create a discount. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + paymentsDiscountsCreate(options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.paymentsDiscountsCreate(options).then((request) => request(axios, basePath)); + }, /** * Retrives the current user\'s completed orders. * @param {PaymentsApiPaymentsOrdersHistoryListRequest} requestParameters Request parameters. @@ -2215,6 +2483,20 @@ export interface PaymentsApiPaymentsBasketsCreateFromProductCreateRequest { readonly system_slug: string } +/** + * Request parameters for paymentsBasketsForSystemRetrieve operation in PaymentsApi. + * @export + * @interface PaymentsApiPaymentsBasketsForSystemRetrieveRequest + */ +export interface PaymentsApiPaymentsBasketsForSystemRetrieveRequest { + /** + * + * @type {string} + * @memberof PaymentsApiPaymentsBasketsForSystemRetrieve + */ + readonly system_slug: string +} + /** * Request parameters for paymentsBasketsList operation in PaymentsApi. * @export @@ -2332,6 +2614,17 @@ export class PaymentsApi extends BaseAPI { return PaymentsApiFp(this.configuration).paymentsBasketsCreateFromProductCreate(requestParameters.sku, requestParameters.system_slug, options).then((request) => request(this.axios, this.basePath)); } + /** + * Returns or creates a basket for the current user and system. + * @param {PaymentsApiPaymentsBasketsForSystemRetrieveRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof PaymentsApi + */ + public paymentsBasketsForSystemRetrieve(requestParameters: PaymentsApiPaymentsBasketsForSystemRetrieveRequest, options?: RawAxiosRequestConfig) { + return PaymentsApiFp(this.configuration).paymentsBasketsForSystemRetrieve(requestParameters.system_slug, options).then((request) => request(this.axios, this.basePath)); + } + /** * Retrives the current user\'s baskets, one per system. * @param {PaymentsApiPaymentsBasketsListRequest} requestParameters Request parameters. @@ -2354,6 +2647,16 @@ export class PaymentsApi extends BaseAPI { return PaymentsApiFp(this.configuration).paymentsBasketsRetrieve(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); } + /** + * Create a discount. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof PaymentsApi + */ + public paymentsDiscountsCreate(options?: RawAxiosRequestConfig) { + return PaymentsApiFp(this.configuration).paymentsDiscountsCreate(options).then((request) => request(this.axios, this.basePath)); + } + /** * Retrives the current user\'s completed orders. * @param {PaymentsApiPaymentsOrdersHistoryListRequest} requestParameters Request parameters. diff --git a/openapi/specs/v0.yaml b/openapi/specs/v0.yaml index 0d982d9d..4267a09d 100644 --- a/openapi/specs/v0.yaml +++ b/openapi/specs/v0.yaml @@ -413,6 +413,25 @@ paths: schema: $ref: '#/components/schemas/BasketWithProduct' description: '' + /api/v0/payments/baskets/for_system/{system_slug}/: + get: + operationId: payments_baskets_for_system_retrieve + description: Returns or creates a basket for the current user and system. + parameters: + - in: path + name: system_slug + schema: + type: string + required: true + tags: + - payments + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/BasketWithProduct' + description: '' /api/v0/payments/discounts/: post: operationId: payments_discounts_create diff --git a/payments/views/v0/__init__.py b/payments/views/v0/__init__.py index 8b1b0d52..6b19ea5d 100644 --- a/payments/views/v0/__init__.py +++ b/payments/views/v0/__init__.py @@ -100,6 +100,32 @@ def get_queryset(self): return Basket.objects.filter(user=self.request.user).all() +@extend_schema( + description="Returns or creates a basket for the current user and system.", + methods=["GET"], + request=None, + responses=BasketWithProductSerializer, +) +@api_view(["GET"]) +@permission_classes((IsAuthenticated,)) +def get_user_basket_for_system(request, system_slug: str): + """ + Return the user's basket for the given system. + + Args: + request: The request object. + system_slug: The system slug. + + Returns: + Basket: The basket object. + """ + system = IntegratedSystem.objects.get(slug=system_slug) + return Response( + BasketWithProductSerializer(Basket.establish_basket(request, system)).data, + status=status.HTTP_200_OK, + ) + + @extend_schema( description=( "Creates or updates a basket for the current user, " diff --git a/payments/views/v0/urls.py b/payments/views/v0/urls.py index dd2a5768..8d6e4e56 100644 --- a/payments/views/v0/urls.py +++ b/payments/views/v0/urls.py @@ -12,6 +12,7 @@ add_discount_to_basket, clear_basket, create_basket_from_product, + get_user_basket_for_system, ) from unified_ecommerce.routers import SimpleRouterWithNesting @@ -24,6 +25,11 @@ router.register(r"checkout", CheckoutApiViewSet, basename="checkout") urlpatterns = [ + path( + "baskets/for_system//", + get_user_basket_for_system, + name="get_user_basket_for_system", + ), path( "baskets/create_from_product///", create_basket_from_product, diff --git a/users/views.py b/users/views.py index ab0a560e..3cabfbf8 100644 --- a/users/views.py +++ b/users/views.py @@ -1,5 +1,7 @@ """Views for the users app.""" +from urllib.parse import urljoin + from django.conf import settings from django.shortcuts import redirect from django.views.generic import TemplateView @@ -45,7 +47,9 @@ def establish_session(request): if "next" in request.GET: try: system = IntegratedSystem.objects.get(slug=request.GET["next"]) - next_url = f"{settings.MITOL_UE_PAYMENT_BASKET_ROOT}{system.slug}/" + next_url = urljoin( + settings.MITOL_UE_PAYMENT_BASKET_ROOT, f"?system={system.slug}" + ) except IntegratedSystem.DoesNotExist: pass