diff --git a/frontends/api/src/generated/v0/api.ts b/frontends/api/src/generated/v0/api.ts index f6c79a1b..05250636 100644 --- a/frontends/api/src/generated/v0/api.ts +++ b/frontends/api/src/generated/v0/api.ts @@ -29,12 +29,6 @@ import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerM * @interface BasketItemWithProduct */ export interface BasketItemWithProduct { - /** - * - * @type {Nested} - * @memberof BasketItemWithProduct - */ - 'basket': Nested; /** * * @type {Product} @@ -78,12 +72,30 @@ export interface BasketWithProduct { * @memberof BasketWithProduct */ 'user': number; + /** + * + * @type {IntegratedSystem} + * @memberof BasketWithProduct + */ + 'integrated_system': IntegratedSystem; /** * * @type {Array} * @memberof BasketWithProduct */ 'basket_items': Array; + /** + * Get the subtotal for the basket + * @type {number} + * @memberof BasketWithProduct + */ + 'subtotal': number; + /** + * Get the tax for the basket + * @type {number} + * @memberof BasketWithProduct + */ + 'tax': number; /** * Get the total price for the basket * @type {number} @@ -190,87 +202,6 @@ export interface Line { */ 'product': Product; } -/** - * - * @export - * @interface Nested - */ -export interface Nested { - /** - * - * @type {number} - * @memberof Nested - */ - 'id': number; - /** - * - * @type {string} - * @memberof Nested - */ - 'created_on': string; - /** - * - * @type {string} - * @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} - * @memberof Nested - */ - 'discounts': Array; -} - - /** * Serializer for order history. * @export @@ -495,12 +426,6 @@ export interface PatchedProductRequest { * @memberof PatchedProductRequest */ 'name'?: string; - /** - * Price (decimal to two places) - * @type {string} - * @memberof PatchedProductRequest - */ - 'price'?: string; /** * Long description of the product. * @type {string} @@ -519,6 +444,12 @@ export interface PatchedProductRequest { * @memberof PatchedProductRequest */ 'system'?: number; + /** + * Price (decimal to two places) + * @type {string} + * @memberof PatchedProductRequest + */ + 'price'?: string; } /** * Serializer for Product model. @@ -532,30 +463,6 @@ export interface Product { * @memberof Product */ 'id': number; - /** - * - * @type {string} - * @memberof Product - */ - 'deleted_on': string | null; - /** - * - * @type {boolean} - * @memberof Product - */ - 'deleted_by_cascade': boolean; - /** - * - * @type {string} - * @memberof Product - */ - 'created_on': string; - /** - * - * @type {string} - * @memberof Product - */ - 'updated_on': string; /** * SKU of the product. * @type {string} @@ -568,12 +475,6 @@ export interface Product { * @memberof Product */ 'name': string; - /** - * Price (decimal to two places) - * @type {string} - * @memberof Product - */ - 'price': string; /** * Long description of the product. * @type {string} @@ -592,6 +493,18 @@ export interface Product { * @memberof Product */ 'system': number; + /** + * Price (decimal to two places) + * @type {string} + * @memberof Product + */ + 'price': string; + /** + * + * @type {boolean} + * @memberof Product + */ + 'deleted_by_cascade': boolean; } /** * Serializer for Product model. @@ -611,12 +524,6 @@ export interface ProductRequest { * @memberof ProductRequest */ 'name': string; - /** - * Price (decimal to two places) - * @type {string} - * @memberof ProductRequest - */ - 'price': string; /** * Long description of the product. * @type {string} @@ -635,6 +542,12 @@ export interface ProductRequest { * @memberof ProductRequest */ 'system': number; + /** + * Price (decimal to two places) + * @type {string} + * @memberof ProductRequest + */ + 'price': string; } /** * * `pending` - Pending * `fulfilled` - Fulfilled * `canceled` - Canceled * `refunded` - Refunded * `declined` - Declined * `errored` - Errored * `review` - Review @@ -687,35 +600,42 @@ export type StateEnum = typeof StateEnum[keyof typeof StateEnum]; /** - * * `profile` - profile * `geoip` - geoip * `none` - none + * Serializer for User model. * @export - * @enum {string} + * @interface User */ - -export const UserTaxableGeolocationTypeEnumDescriptions = { - 'profile': "profile", - 'geoip': "geoip", - 'none': "none", -} as const; - -export const UserTaxableGeolocationTypeEnum = { +export interface User { /** - * profile - */ - Profile: 'profile', + * + * @type {number} + * @memberof User + */ + 'id': number; /** - * geoip - */ - Geoip: 'geoip', + * Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. + * @type {string} + * @memberof User + */ + 'username': string; /** - * none - */ - None: 'none' -} as const; - -export type UserTaxableGeolocationTypeEnum = typeof UserTaxableGeolocationTypeEnum[keyof typeof UserTaxableGeolocationTypeEnum]; - - + * + * @type {string} + * @memberof User + */ + 'email'?: string; + /** + * + * @type {string} + * @memberof User + */ + 'first_name'?: string; + /** + * + * @type {string} + * @memberof User + */ + 'last_name'?: string; +} /** * MetaApi - axios parameter creator @@ -2456,3 +2376,100 @@ export class PaymentsApi extends BaseAPI { return PaymentsApiFp(this.configuration).paymentsOrdersHistoryRetrieve(requestParameters.id, options).then((request) => request(this.axios, this.basePath)); } } + + + +/** + * UsersApi - axios parameter creator + * @export + */ +export const UsersApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * User retrieve and update viewsets for the current user + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + usersMeRetrieve: async (options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/api/v0/users/me/`; + // 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}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * UsersApi - functional programming interface + * @export + */ +export const UsersApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = UsersApiAxiosParamCreator(configuration) + return { + /** + * User retrieve and update viewsets for the current user + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async usersMeRetrieve(options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.usersMeRetrieve(options); + const index = configuration?.serverIndex ?? 0; + const operationBasePath = operationServerMap['UsersApi.usersMeRetrieve']?.[index]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); + }, + } +}; + +/** + * UsersApi - factory interface + * @export + */ +export const UsersApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = UsersApiFp(configuration) + return { + /** + * User retrieve and update viewsets for the current user + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + usersMeRetrieve(options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.usersMeRetrieve(options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * UsersApi - object-oriented interface + * @export + * @class UsersApi + * @extends {BaseAPI} + */ +export class UsersApi extends BaseAPI { + /** + * User retrieve and update viewsets for the current user + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof UsersApi + */ + public usersMeRetrieve(options?: RawAxiosRequestConfig) { + return UsersApiFp(this.configuration).usersMeRetrieve(options).then((request) => request(this.axios, this.basePath)); + } +} diff --git a/openapi/specs/v0.yaml b/openapi/specs/v0.yaml index 8ad471bf..635b354f 100644 --- a/openapi/specs/v0.yaml +++ b/openapi/specs/v0.yaml @@ -458,16 +458,27 @@ paths: schema: $ref: '#/components/schemas/OrderHistory' description: '' + /api/v0/users/me/: + get: + operationId: users_me_retrieve + description: User retrieve and update viewsets for the current user + tags: + - users + security: + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/User' + description: '' components: schemas: BasketItemWithProduct: type: object description: Basket item model serializer with product information properties: - basket: - allOf: - - $ref: '#/components/schemas/Nested' - readOnly: true product: $ref: '#/components/schemas/Product' id: @@ -488,7 +499,6 @@ components: Decimal: The price of the basket item reduced by an applicable discount. readOnly: true required: - - basket - discounted_price - id - price @@ -502,10 +512,22 @@ components: readOnly: true user: type: integer + integrated_system: + $ref: '#/components/schemas/IntegratedSystem' basket_items: type: array items: $ref: '#/components/schemas/BasketItemWithProduct' + subtotal: + type: number + format: double + description: Get the subtotal for the basket + readOnly: true + tax: + type: number + format: double + description: Get the tax for the basket + readOnly: true total_price: type: number format: double @@ -514,6 +536,9 @@ components: required: - basket_items - id + - integrated_system + - subtotal + - tax - total_price - user IntegratedSystem: @@ -583,66 +608,6 @@ components: - quantity - total_price - unit_price - Nested: - type: object - properties: - id: - type: integer - readOnly: true - created_on: - type: string - format: date-time - readOnly: true - updated_on: - type: string - format: date-time - readOnly: true - user_ip: - type: string - description: The IP address of the user. - maxLength: 46 - user_taxable_country_code: - type: string - nullable: true - description: The country code for the user for this basket for tax purposes. - maxLength: 2 - user_taxable_geolocation_type: - allOf: - - $ref: '#/components/schemas/UserTaxableGeolocationTypeEnum' - description: |- - How the user's location was determined for tax purposes. - - * `profile` - profile - * `geoip` - geoip - * `none` - none - user_blockable_country_code: - type: string - nullable: true - description: The country code for the user for this basket for blocked items. - maxLength: 2 - user_blockable_geolocation_type: - type: string - description: How the user's location was determined for blocked items. - maxLength: 15 - user: - type: integer - integrated_system: - type: integer - tax_rate: - type: integer - nullable: true - description: The tax rate assessed for this basket. - discounts: - type: array - items: - type: integer - required: - - created_on - - discounts - - id - - integrated_system - - updated_on - - user OrderHistory: type: object description: Serializer for order history. @@ -800,11 +765,6 @@ components: minLength: 1 description: Short name of the product, displayed in carts/etc. maxLength: 255 - price: - type: string - format: decimal - pattern: ^-?\d{0,5}(?:\.\d{0,2})?$ - description: Price (decimal to two places) description: type: string minLength: 1 @@ -815,6 +775,11 @@ components: system: type: integer description: Owner system of the product. + price: + type: string + format: decimal + pattern: ^-?\d{0,5}(?:\.\d{0,2})?$ + description: Price (decimal to two places) Product: type: object description: Serializer for Product model. @@ -822,22 +787,6 @@ components: id: type: integer readOnly: true - deleted_on: - type: string - format: date-time - readOnly: true - nullable: true - deleted_by_cascade: - type: boolean - readOnly: true - created_on: - type: string - format: date-time - readOnly: true - updated_on: - type: string - format: date-time - readOnly: true sku: type: string description: SKU of the product. @@ -846,11 +795,6 @@ components: type: string description: Short name of the product, displayed in carts/etc. maxLength: 255 - price: - type: string - format: decimal - pattern: ^-?\d{0,5}(?:\.\d{0,2})?$ - description: Price (decimal to two places) description: type: string description: Long description of the product. @@ -860,17 +804,22 @@ components: system: type: integer description: Owner system of the product. + price: + type: string + format: decimal + pattern: ^-?\d{0,5}(?:\.\d{0,2})?$ + description: Price (decimal to two places) + deleted_by_cascade: + type: boolean + readOnly: true required: - - created_on - deleted_by_cascade - - deleted_on - description - id - name - price - sku - system - - updated_on ProductRequest: type: object description: Serializer for Product model. @@ -885,11 +834,6 @@ components: minLength: 1 description: Short name of the product, displayed in carts/etc. maxLength: 255 - price: - type: string - format: decimal - pattern: ^-?\d{0,5}(?:\.\d{0,2})?$ - description: Price (decimal to two places) description: type: string minLength: 1 @@ -900,6 +844,11 @@ components: system: type: integer description: Owner system of the product. + price: + type: string + format: decimal + pattern: ^-?\d{0,5}(?:\.\d{0,2})?$ + description: Price (decimal to two places) required: - description - name @@ -932,17 +881,30 @@ components: - Declined - Errored - Review - UserTaxableGeolocationTypeEnum: - enum: - - profile - - geoip - - none - type: string - description: |- - * `profile` - profile - * `geoip` - geoip - * `none` - none - x-enum-descriptions: - - profile - - geoip - - none + User: + type: object + description: Serializer for User model. + properties: + id: + type: integer + readOnly: true + username: + type: string + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + pattern: ^[\w.@+-]+$ + maxLength: 150 + email: + type: string + format: email + title: Email address + maxLength: 254 + first_name: + type: string + maxLength: 150 + last_name: + type: string + maxLength: 150 + required: + - id + - username diff --git a/payments/models.py b/payments/models.py index 7f9701f0..a72c04c8 100644 --- a/payments/models.py +++ b/payments/models.py @@ -456,7 +456,7 @@ def tax_money(self) -> Decimal: def total_money(self) -> Decimal: """Return the total for the basket, including discounts and tax.""" - return quantize_decimal(self.total_money) + return quantize_decimal(self.total) @staticmethod def establish_basket(request, integrated_system: IntegratedSystem): diff --git a/payments/serializers/v0/__init__.py b/payments/serializers/v0/__init__.py index d03516ab..362a00f4 100644 --- a/payments/serializers/v0/__init__.py +++ b/payments/serializers/v0/__init__.py @@ -13,7 +13,7 @@ ) from payments.models import Basket, BasketItem, Line, Order from system_meta.models import Product -from system_meta.serializers import ProductSerializer +from system_meta.serializers import IntegratedSystemSerializer, ProductSerializer from unified_ecommerce.serializers import UserSerializer User = get_user_model() @@ -74,6 +74,7 @@ class BasketSerializer(serializers.ModelSerializer): """Basket model serializer""" basket_items = BasketItemSerializer(many=True) + integrated_system = IntegratedSystemSerializer() class Meta: """Meta options for BasketSerializer""" @@ -81,6 +82,7 @@ class Meta: fields = [ "id", "user", + "integrated_system", "basket_items", ] model = Basket @@ -95,7 +97,7 @@ class Meta: """Meta options for BasketItemWithProductSerializer""" model = BasketItem - fields = ["basket", "product", "id", "price", "discounted_price"] + fields = ["product", "id", "price", "discounted_price"] depth = 1 @@ -104,12 +106,21 @@ class BasketWithProductSerializer(serializers.ModelSerializer): basket_items = BasketItemWithProductSerializer(many=True) total_price = serializers.SerializerMethodField() + tax = serializers.SerializerMethodField() + subtotal = serializers.SerializerMethodField() + integrated_system = IntegratedSystemSerializer() def get_total_price(self, instance) -> Decimal: """Get the total price for the basket""" - return sum( - basket_item.base_price for basket_item in instance.basket_items.all() - ) + return instance.total_money + + def get_tax(self, instance) -> Decimal: + """Get the tax for the basket""" + return instance.tax_money + + def get_subtotal(self, instance) -> Decimal: + """Get the subtotal for the basket""" + return instance.subtotal_money class Meta: """Meta options for BasketWithProductSerializer""" @@ -117,7 +128,10 @@ class Meta: fields = [ "id", "user", + "integrated_system", "basket_items", + "subtotal", + "tax", "total_price", ] model = Basket diff --git a/system_meta/serializers.py b/system_meta/serializers.py index 256285c9..8aa8dda1 100644 --- a/system_meta/serializers.py +++ b/system_meta/serializers.py @@ -32,4 +32,13 @@ class Meta: """Meta class for serializer.""" model = Product - fields = "__all__" + fields = [ + "id", + "sku", + "name", + "description", + "system_data", + "system", + "price", + "deleted_by_cascade", + ] diff --git a/users/urls.py b/users/urls.py index 5ec54b1d..189579e9 100644 --- a/users/urls.py +++ b/users/urls.py @@ -27,5 +27,5 @@ establish_session, name="users-establish_session", ), - re_path(r"^api/v0/users/", include(v0_urls)), + re_path(r"^api/v0/users/", include((v0_urls, "v0"))), ]