Skip to content

Commit

Permalink
Add tax collection and blocked countries processing (#166)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkachel authored Nov 14, 2024
1 parent 5b92afd commit 1dcfe17
Show file tree
Hide file tree
Showing 45 changed files with 3,080 additions and 882 deletions.
44 changes: 38 additions & 6 deletions cart/templates/cart.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,61 @@
<th scope="col">Product</th>
<th scope="col">Price</th>
<th scope="col">Quantity</th>
<th scope="col">Discount code</th>
<th scope="col">Discount Code</th>
<th scope="col">Subtotal</th>
<th scope="col">Tax</th>
<th scope="col">Total</th>
</tr>
</thead>
<tbody>
{% if basket_items|length == 0 %}
<tr>
<td colspan="4">No items in the basket.</td>
<td colspan="7">No items in the basket.</td>
</tr>
{% endif %}
{% for item in basket_items %}
<tr>
<td>{{ item.product }}</td>
<td>{{ item.product.price }}</td>
<td>{{ item.product.price_money }}</td>
<td>{{ item.quantity }}</td>
<td>{{ item.best_discount_for_item_from_basket.discount_code }}</td>
<td>{{ item.price }}</td>
<td>
{% if item.best_discount_for_item_from_basket %}
{{ item.best_discount_for_item_from_basket.discount_code }}
{% endif %}
</td>
<td>
{% if item.best_discount_for_item_from_basket %}
{{ item.discounted_price_money }}
{% endif %}
</td>
<td>
{% if item.basket.tax_rate %}
{{ item.tax_money }}
{% else %}
<em>None</em>
{% endif %}
<td>{{ item.total_price_money }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="4">
<td>
<strong>Totals:</strong>
</td>
<td colspan="3"></td>
<td>
{{ basket.subtotal }}
</td>
<td>
{{ basket.tax }}
</td>
<td>
{{ basket.total }}
</td>
</tr>
<tr>
<td colspan="7">
<a href="{% url 'checkout_interstitial_page' system_slug=basket.integrated_system.slug %}" class="btn btn-primary float-end">Check Out</a>
</td>
</tr>
Expand Down
4 changes: 3 additions & 1 deletion cart/templates/checkout_interstitial.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ <h1 class="mt-4">Redirecting to the payment processor...</h1>

<div>
<button class="btn btn-primary" type="submit">Redirect to CyberSource in <span id="countdown-time">5</span></button>

<button class="btn btn-danger" type="button" onclick="clearInterval(checkoutInterval);">Cancel Redirect</button>
</div>
{% else %}
{% for key, value in form.items %}
Expand All @@ -33,7 +35,7 @@ <h1 class="mt-4">Redirecting to the payment processor...</h1>
<script type="text/javascript">
var counter = 5;

setInterval(function() {
var checkoutInterval = setInterval(function() {
counter--;

document.getElementById('countdown-time').innerHTML = counter;
Expand Down
208 changes: 200 additions & 8 deletions frontends/api/src/generated/v0/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ export interface BasketItemWithProduct {
* @memberof BasketItemWithProduct
*/
'id': number;
/**
* Return the total price of the basket item with discounts.
* @type {number}
* @memberof BasketItemWithProduct
*/
'price': number;
/**
* Get the price of the basket item with applicable discounts. Returns: Decimal: The price of the basket item reduced by an applicable discount.
* @type {number}
* @memberof BasketItemWithProduct
*/
'discounted_price': number;
}
/**
* Basket model serializer with items and products
Expand Down Expand Up @@ -202,13 +214,63 @@ export interface Nested {
* @memberof Nested
*/
'updated_on': string;
/**
* The IP address of the user.
* @type {string}
* @memberof Nested
*/
'user_ip'?: string;
/**
* The country code for the user for this basket for tax purposes.
* @type {string}
* @memberof Nested
*/
'user_taxable_country_code'?: string | null;
/**
*
* @type {UserTaxableGeolocationTypeEnum}
* @memberof Nested
*/
'user_taxable_geolocation_type'?: UserTaxableGeolocationTypeEnum;
/**
* The country code for the user for this basket for blocked items.
* @type {string}
* @memberof Nested
*/
'user_blockable_country_code'?: string | null;
/**
* How the user\'s location was determined for blocked items.
* @type {string}
* @memberof Nested
*/
'user_blockable_geolocation_type'?: string;
/**
*
* @type {number}
* @memberof Nested
*/
'user': number;
/**
*
* @type {number}
* @memberof Nested
*/
'integrated_system': number;
/**
* The tax rate assessed for this basket.
* @type {number}
* @memberof Nested
*/
'tax_rate'?: number | null;
/**
*
* @type {Array<number>}
* @memberof Nested
*/
'discounts': Array<number>;
}


/**
* Serializer for order history.
* @export
Expand Down Expand Up @@ -624,6 +686,36 @@ export const StateEnum = {
export type StateEnum = typeof StateEnum[keyof typeof StateEnum];


/**
* * `profile` - profile * `geoip` - geoip * `none` - none
* @export
* @enum {string}
*/

export const UserTaxableGeolocationTypeEnumDescriptions = {
'profile': "profile",
'geoip': "geoip",
'none': "none",
} as const;

export const UserTaxableGeolocationTypeEnum = {
/**
* profile
*/
Profile: 'profile',
/**
* geoip
*/
Geoip: 'geoip',
/**
* none
*/
None: 'none'
} as const;

export type UserTaxableGeolocationTypeEnum = typeof UserTaxableGeolocationTypeEnum[keyof typeof UserTaxableGeolocationTypeEnum];



/**
* MetaApi - axios parameter creator
Expand Down Expand Up @@ -1728,13 +1820,50 @@ export class MetaApi extends BaseAPI {
*/
export const PaymentsApiAxiosParamCreator = function (configuration?: Configuration) {
return {
/**
* Creates or updates a basket for the current user, adding the discount if valid.
* @param {string} system_slug
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
paymentsBasketsAddDiscountCreate: async (system_slug: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'system_slug' is not null or undefined
assertParamExists('paymentsBasketsAddDiscountCreate', 'system_slug', system_slug)
const localVarPath = `/api/v0/payments/baskets/add_discount/{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: '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};

return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Clears the basket for the current user.
* @param {string} system_slug
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
paymentsBasketsClearDestroy: async (options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/v0/payments/baskets/clear/`;
paymentsBasketsClearDestroy: async (system_slug: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'system_slug' is not null or undefined
assertParamExists('paymentsBasketsClearDestroy', 'system_slug', system_slug)
const localVarPath = `/api/v0/payments/baskets/clear/{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;
Expand Down Expand Up @@ -1948,13 +2077,26 @@ export const PaymentsApiAxiosParamCreator = function (configuration?: Configurat
export const PaymentsApiFp = function(configuration?: Configuration) {
const localVarAxiosParamCreator = PaymentsApiAxiosParamCreator(configuration)
return {
/**
* Creates or updates a basket for the current user, adding the discount if valid.
* @param {string} system_slug
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async paymentsBasketsAddDiscountCreate(system_slug: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<BasketWithProduct>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.paymentsBasketsAddDiscountCreate(system_slug, options);
const index = configuration?.serverIndex ?? 0;
const operationBasePath = operationServerMap['PaymentsApi.paymentsBasketsAddDiscountCreate']?.[index]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
},
/**
* Clears the basket for the current user.
* @param {string} system_slug
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async paymentsBasketsClearDestroy(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.paymentsBasketsClearDestroy(options);
async paymentsBasketsClearDestroy(system_slug: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.paymentsBasketsClearDestroy(system_slug, options);
const index = configuration?.serverIndex ?? 0;
const operationBasePath = operationServerMap['PaymentsApi.paymentsBasketsClearDestroy']?.[index]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
Expand Down Expand Up @@ -2032,13 +2174,23 @@ export const PaymentsApiFp = function(configuration?: Configuration) {
export const PaymentsApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
const localVarFp = PaymentsApiFp(configuration)
return {
/**
* Creates or updates a basket for the current user, adding the discount if valid.
* @param {PaymentsApiPaymentsBasketsAddDiscountCreateRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
paymentsBasketsAddDiscountCreate(requestParameters: PaymentsApiPaymentsBasketsAddDiscountCreateRequest, options?: RawAxiosRequestConfig): AxiosPromise<BasketWithProduct> {
return localVarFp.paymentsBasketsAddDiscountCreate(requestParameters.system_slug, options).then((request) => request(axios, basePath));
},
/**
* Clears the basket for the current user.
* @param {PaymentsApiPaymentsBasketsClearDestroyRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
paymentsBasketsClearDestroy(options?: RawAxiosRequestConfig): AxiosPromise<void> {
return localVarFp.paymentsBasketsClearDestroy(options).then((request) => request(axios, basePath));
paymentsBasketsClearDestroy(requestParameters: PaymentsApiPaymentsBasketsClearDestroyRequest, options?: RawAxiosRequestConfig): AxiosPromise<void> {
return localVarFp.paymentsBasketsClearDestroy(requestParameters.system_slug, options).then((request) => request(axios, basePath));
},
/**
* Creates or updates a basket for the current user, adding the selected product.
Expand Down Expand Up @@ -2088,6 +2240,34 @@ export const PaymentsApiFactory = function (configuration?: Configuration, baseP
};
};

/**
* Request parameters for paymentsBasketsAddDiscountCreate operation in PaymentsApi.
* @export
* @interface PaymentsApiPaymentsBasketsAddDiscountCreateRequest
*/
export interface PaymentsApiPaymentsBasketsAddDiscountCreateRequest {
/**
*
* @type {string}
* @memberof PaymentsApiPaymentsBasketsAddDiscountCreate
*/
readonly system_slug: string
}

/**
* Request parameters for paymentsBasketsClearDestroy operation in PaymentsApi.
* @export
* @interface PaymentsApiPaymentsBasketsClearDestroyRequest
*/
export interface PaymentsApiPaymentsBasketsClearDestroyRequest {
/**
*
* @type {string}
* @memberof PaymentsApiPaymentsBasketsClearDestroy
*/
readonly system_slug: string
}

/**
* Request parameters for paymentsBasketsCreateFromProductCreate operation in PaymentsApi.
* @export
Expand Down Expand Up @@ -2186,14 +2366,26 @@ export interface PaymentsApiPaymentsOrdersHistoryRetrieveRequest {
* @extends {BaseAPI}
*/
export class PaymentsApi extends BaseAPI {
/**
* Creates or updates a basket for the current user, adding the discount if valid.
* @param {PaymentsApiPaymentsBasketsAddDiscountCreateRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof PaymentsApi
*/
public paymentsBasketsAddDiscountCreate(requestParameters: PaymentsApiPaymentsBasketsAddDiscountCreateRequest, options?: RawAxiosRequestConfig) {
return PaymentsApiFp(this.configuration).paymentsBasketsAddDiscountCreate(requestParameters.system_slug, options).then((request) => request(this.axios, this.basePath));
}

/**
* Clears the basket for the current user.
* @param {PaymentsApiPaymentsBasketsClearDestroyRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof PaymentsApi
*/
public paymentsBasketsClearDestroy(options?: RawAxiosRequestConfig) {
return PaymentsApiFp(this.configuration).paymentsBasketsClearDestroy(options).then((request) => request(this.axios, this.basePath));
public paymentsBasketsClearDestroy(requestParameters: PaymentsApiPaymentsBasketsClearDestroyRequest, options?: RawAxiosRequestConfig) {
return PaymentsApiFp(this.configuration).paymentsBasketsClearDestroy(requestParameters.system_slug, options).then((request) => request(this.axios, this.basePath));
}

/**
Expand Down
4 changes: 4 additions & 0 deletions openapi/apps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
"""Config for the OpenAPI app."""

from django.apps import AppConfig


class OpenapiConfig(AppConfig):
"""Config for the OpenAPI app."""

default_auto_field = "django.db.models.BigAutoField"
name = "openapi"
Loading

0 comments on commit 1dcfe17

Please sign in to comment.