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