From d2a2c10bdb8296a223d80e32c1b78ea14833364f Mon Sep 17 00:00:00 2001 From: Daniel Collins Date: Tue, 1 Oct 2019 00:19:47 +1000 Subject: [PATCH] Teach ts sdk about product utility members --- typescript/package.json | 2 + typescript/src/entities/domain.ts | 24 ++++ typescript/src/entities/product.test.ts | 129 +++++++++++++++++ typescript/src/entities/product.ts | 134 ++++++++++++++++++ .../src/entities/variation_field.test.ts | 30 ++++ typescript/src/entities/variation_field.ts | 58 +++++++- typescript/yarn.lock | 10 ++ 7 files changed, 386 insertions(+), 1 deletion(-) diff --git a/typescript/package.json b/typescript/package.json index 834d286a..b18831d4 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -17,7 +17,9 @@ "typescript": "^3.4.5" }, "dependencies": { + "@types/lodash": "^4.14.141", "@types/node": "^12.0.2", + "lodash": "^4.17.15", "reflect-metadata": "^0.1.13" } } diff --git a/typescript/src/entities/domain.ts b/typescript/src/entities/domain.ts index ecde027a..841e2e0f 100644 --- a/typescript/src/entities/domain.ts +++ b/typescript/src/entities/domain.ts @@ -124,4 +124,28 @@ export class Domain extends Entity { @Domain.property({arrayType: "Theme"}) public themes?: Array; + + public defaultCurrency = () => { + if (this.company === undefined) { + throw new Error("company is undefined, did you forget to embed it?"); + } + if (this.company.defaultCurrency === undefined) { + const err = "company.defaultCurrency is undefined, did you forget to" + + " embed it?"; + throw new Error(err); + } + return this.company.defaultCurrency; + } + + public defaultTaxType = () => { + if (this.company === undefined) { + throw new Error("company is undefined, did you forget to embed it?"); + } + if (this.company.defaultTaxType === undefined) { + const err = "company.defaultTaxType is undefined, did you forget to" + + " embed it?"; + throw new Error(err); + } + return this.company.defaultTaxType; + } } diff --git a/typescript/src/entities/product.test.ts b/typescript/src/entities/product.test.ts index 52102b9f..14e3e854 100644 --- a/typescript/src/entities/product.test.ts +++ b/typescript/src/entities/product.test.ts @@ -328,4 +328,133 @@ test('primary key always serialised', () => { }); }); +test('duplicate', () => { + const merchi = new Merchi(); + const product = new merchi.Product(); + const testName = 'qkc6fYD8HkR'; + mockFetch(true, {'product': {'name': testName}}, 200); + return product.duplicate().then(clone => { + expect(clone.name).toEqual(testName); + }); +}); + +test('primaryImage', () => { + const merchi = new Merchi(); + const product = new merchi.Product(); + const i1 = new merchi.MerchiFile(); + const i2 = new merchi.MerchiFile(); + expect(product.primaryImage).toThrow(); + product.featureImage = i1; + expect(product.primaryImage).toThrow(); + product.images = [i2]; + expect(product.primaryImage()).toBe(i1); + product.featureImage = null; + expect(product.primaryImage()).toBe(i2); + product.images = []; + expect(product.primaryImage()).toBe(null); +}); + +test('currency', () => { + const merchi = new Merchi(); + const product = new merchi.Product(); + expect(product.currency).toThrow(); + product.domain = new merchi.Domain(); + expect(product.currency).toThrow(); + product.domain.company = new merchi.Company(); + expect(product.currency).toThrow(); + product.domain.company.defaultCurrency = "MMK"; + expect(product.currency()).toEqual("MMK"); +}); + +test('hasGroupVariationFields', () => { + const merchi = new Merchi(); + const product = new merchi.Product(); + expect(product.hasGroupVariationFields).toThrow(); + product.groupVariationFields = []; + expect(product.hasGroupVariationFields()).toBe(false); + product.groupVariationFields = [new merchi.VariationField()]; + expect(product.hasGroupVariationFields()).toBe(true); +}); + +test('hasIndependentVariationFields', () => { + const merchi = new Merchi(); + const product = new merchi.Product(); + expect(product.hasIndependentVariationFields).toThrow(); + product.independentVariationFields = []; + expect(product.hasIndependentVariationFields()).toBe(false); + product.independentVariationFields = [new merchi.VariationField()]; + expect(product.hasIndependentVariationFields()).toBe(true); +}); + +test('taxType', () => { + const merchi = new Merchi(); + const product = new merchi.Product(); + expect(product.taxType).toThrow(); + product.domain = new merchi.Domain(); + expect(product.taxType).toThrow(); + product.domain.company = new merchi.Company(); + expect(product.taxType).toThrow(); + const tax = new merchi.CountryTax(); + product.domain.company.defaultTaxType = tax; + expect(product.taxType()).toBe(tax); + product.domain.company.defaultTaxType = null; + expect(product.taxType()).toBe(null); +}); + +test('allVariationFields', () => { + const merchi = new Merchi(); + const product = new merchi.Product(); + const vf1 = new merchi.VariationField(); + const vf2 = new merchi.VariationField(); + expect(product.allVariationFields).toThrow(); + product.groupVariationFields = [vf1]; + expect(product.allVariationFields).toThrow(); + product.independentVariationFields = [vf2]; + expect(product.allVariationFields()).toEqual([vf1, vf2]); +}); + +test('removeVariationField', () => { + const merchi = new Merchi(); + const product = new merchi.Product(); + const vf = new merchi.VariationField(); + expect(() => product.removeVariationField(vf)).toThrow(); + vf.independent = false; + expect(() => product.removeVariationField(vf)).toThrow(); + product.independentVariationFields = []; + expect(() => product.removeVariationField(vf)).toThrow(); + product.groupVariationFields = [vf]; + expect(() => product.removeVariationField(vf)).toThrow(); + vf.id = 1; + expect(product.removeVariationField(vf).length).toEqual(1); + expect(product.groupVariationFields.length).toEqual(0); + vf.independent = true; + product.independentVariationFields = [vf]; + expect(product.removeVariationField(vf).length).toEqual(1); + expect(product.independentVariationFields.length).toEqual(0); +}); + +test('buildEmptyVariations', () => { + const merchi = new Merchi(); + const product = new merchi.Product(); + expect(product.buildEmptyVariations).toThrow(); + product.independentVariationFields = []; + expect(product.buildEmptyVariations()).toEqual([]); + product.independentVariationFields = [new merchi.VariationField()]; + product.independentVariationFields[0].defaultValue = ""; + product.independentVariationFields[0].fieldType = 11; + product.independentVariationFields[0].variationCost = 2; + product.independentVariationFields[0].options = []; + expect(product.buildEmptyVariations().length).toEqual(1); +}); +test('buildEmptyVariationGroup', () => { + const merchi = new Merchi(); + const product = new merchi.Product(); + expect(product.buildEmptyVariationGroup).toThrow(); + product.groupVariationFields = [new merchi.VariationField()]; + product.groupVariationFields[0].defaultValue = ""; + product.groupVariationFields[0].fieldType = 11; + product.groupVariationFields[0].variationCost = 2; + product.groupVariationFields[0].options = []; + expect(product.buildEmptyVariationGroup().groupCost).toEqual(0); +}); diff --git a/typescript/src/entities/product.ts b/typescript/src/entities/product.ts index 939425b9..83e467ed 100644 --- a/typescript/src/entities/product.ts +++ b/typescript/src/entities/product.ts @@ -139,4 +139,138 @@ export class Product extends Entity { @Product.property({arrayType: "User"}) public suppliers?: Array; + + public duplicate = () => { + /* create a clone of this product on the backend, returning it. */ + const resourceName = (this.constructor as typeof Product).resourceName; + const resource = `/${resourceName}/${String(this.id)}/copy/`; + const fetchOptions = {method: 'POST'}; + return this.merchi.authenticatedFetch(resource, fetchOptions). + then((data: any) => { + const product = new this.merchi.Product(); + product.fromJson(data); + return product; + }); + } + + public primaryImage = () => { + if (this.featureImage === undefined) { + throw new Error("featureImage is undefined, did you forget to embed it?"); + } + if (this.images === undefined) { + throw new Error("images is undefined, did you forget to embed it?"); + } + if (this.featureImage !== null) { + return this.featureImage; + } + if (this.images.length > 0) { + return this.images[0]; + } + return null; + } + + public currency = () => { + if (this.domain === undefined) { + throw new Error("domain is undefined, did you forget to embed it?"); + } + return this.domain.defaultCurrency(); + } + + public hasGroupVariationFields = () => { + if (this.groupVariationFields === undefined) { + const err = "groupVariationFields is undefined, did you forget to embed" + + " it?"; + throw new Error(err); + } + return this.groupVariationFields.length > 0; + } + + public hasIndependentVariationFields = () => { + if (this.independentVariationFields === undefined) { + const err = "independentVariationFields is undefined, did you forget to" + + " embed it?"; + throw new Error(err); + } + return this.independentVariationFields.length > 0; + } + + public taxType = () => { + if (this.domain === undefined) { + throw new Error("domain is undefined, did you forget to embed it?"); + } + return this.domain.defaultTaxType(); + } + + public allVariationFields = () => { + if (this.groupVariationFields === undefined) { + const err = "groupVariationFields is undefined, did you forget to embed" + + " it?"; + throw new Error(err); + } + if (this.independentVariationFields === undefined) { + const err = "independentVariationFields is undefined, did you forget to" + + " embed it?"; + throw new Error(err); + } + const result: Array = []; + return result.concat(this.groupVariationFields, + this.independentVariationFields); + } + + public buildEmptyVariations = () => { + if (this.independentVariationFields === undefined) { + const err = "independentVariationFields is undefined, did you forget to" + + " embed it?"; + throw new Error(err); + } + return this.independentVariationFields.map(field => + field.buildEmptyVariation()); + } + + public buildEmptyVariationGroup = () => { + if (this.groupVariationFields === undefined) { + const err = "groupVariationFields is undefined, did you forget to embed" + + " it?"; + throw new Error(err); + } + const result = new this.merchi.VariationsGroup(); + const variations = []; + let cost = 0; + result.quantity = 0; + for (const variationField of this.groupVariationFields) { + const empty = variationField.buildEmptyVariation(); + variations.push(empty); + cost += empty.cost as number; + } + result.groupCost = cost; + result.variations = variations; + return result; + } + + public removeVariationField = (variationField: VariationField) => { + if (variationField.independent === undefined) { + throw new Error("variation.independent is undefined, did you " + + "forget to embed it?"); + } + if (this.independentVariationFields === undefined) { + const err = "independentVariationFields is undefined, did you forget to" + + " embed it?"; + throw new Error(err); + } + if (this.groupVariationFields === undefined) { + const err = "groupVariationFields is undefined, did you forget to embed" + + " it?"; + throw new Error(err); + } + const variationFields = variationField.independent ? + this.independentVariationFields : this.groupVariationFields; + const index = variationFields.findIndex(v => { + if (v.id === undefined) { + throw new Error("variation id is undefined, did you forget to " + + "embed it?"); + } + return v.id === variationField.id; + }); + return variationFields.splice(index, 1); + } } diff --git a/typescript/src/entities/variation_field.test.ts b/typescript/src/entities/variation_field.test.ts index b5bf1c66..d84711f2 100644 --- a/typescript/src/entities/variation_field.test.ts +++ b/typescript/src/entities/variation_field.test.ts @@ -5,3 +5,33 @@ test('can make VariationField', () => { const variationField = new merchi.VariationField(); expect(variationField).toBeTruthy(); }); + +test('isSelectable', () => { + const merchi = new Merchi(); + const vf = new merchi.VariationField(); + expect(vf.isSelectable).toThrow(); + vf.fieldType = 1; + expect(vf.isSelectable()).toBe(false); + vf.fieldType = 11; + expect(vf.isSelectable()).toBe(true); +}); + +test('buildEmptyVariation', () => { + const merchi = new Merchi(); + const vf = new merchi.VariationField(); + expect(vf.buildEmptyVariation).toThrow(); + vf.defaultValue = "a"; + vf.fieldType = 11; + expect(vf.buildEmptyVariation).toThrow(); + vf.variationCost = 2; + expect(vf.buildEmptyVariation).toThrow(); + const o1 = new merchi.VariationFieldsOption(); + const o2 = new merchi.VariationFieldsOption(); + o1.default = true; + vf.options = [o1, o2]; + expect(vf.buildEmptyVariation).toThrow(); + o1.variationCost = 3; + expect(vf.buildEmptyVariation().onceOffCost).toEqual(3); + vf.fieldType = 1; + expect(vf.buildEmptyVariation().onceOffCost).toEqual(2); +}); diff --git a/typescript/src/entities/variation_field.ts b/typescript/src/entities/variation_field.ts index 0c905a29..82981f48 100644 --- a/typescript/src/entities/variation_field.ts +++ b/typescript/src/entities/variation_field.ts @@ -1,7 +1,9 @@ +import * as _ from "lodash"; import { Entity } from '../entity'; import { Product } from './product'; import { Variation } from './variation'; import { VariationFieldsOption } from './variation_fields_option'; +import { FieldType } from '../constants/field_types'; export class VariationField extends Entity { protected static resourceName: string = "variation_fields"; @@ -33,7 +35,7 @@ export class VariationField extends Entity { public defaultValue?: string; @VariationField.property() - public fieldType?: number; + public fieldType?: FieldType; @VariationField.property() public variationCost?: number; @@ -88,4 +90,58 @@ export class VariationField extends Entity { @VariationField.property({arrayType: "VariationFieldsOption"}) public options?: Array; + + public isSelectable = () => { + if (this.fieldType === undefined) { + throw new Error("fieldType is undefined, did you forget to embed it?"); + } + const selectable = new Set([FieldType.SELECT, + FieldType.CHECKBOX, + FieldType.RADIO, + FieldType.IMAGE_SELECT, + FieldType.COLOUR_SELECT]); + return selectable.has(this.fieldType); + } + + public buildEmptyVariation = () => { + if (this.defaultValue === undefined) { + throw new Error("defaultValue is undefined, did you forget to embed it?"); + } + if (this.variationCost === undefined) { + const err = "variationCost is undefined, did you forget to embed it?"; + throw new Error(err); + } + if (this.options === undefined) { + throw new Error("options is undefined, did you forget to embed it?"); + } + const result = new this.merchi.Variation(this.merchi); + if (this.isSelectable()) { + let onceOffCost = 0; + const value = []; + for (const option of this.options) { + if (option.default) { + if (option.variationCost === undefined) { + throw new Error("option.variationCost is undefined, did you " + + "forget to embed it?"); + } + value.push(option.id); + onceOffCost += option.variationCost; + } + } + result.value = value.join(); + result.onceOffCost = onceOffCost; + } else { + result.value = this.defaultValue; + result.onceOffCost = this.variationCost; + } + result.unitCostTotal = 0; + result.cost = result.onceOffCost; + function customiser(value: any, index: any) { + if (index === 'merchi') { + return value; + } + } + result.variationField = _.cloneDeepWith(this, customiser); + return result; + } } diff --git a/typescript/yarn.lock b/typescript/yarn.lock index 66974d93..1ec88c6b 100644 --- a/typescript/yarn.lock +++ b/typescript/yarn.lock @@ -350,6 +350,11 @@ dependencies: "@types/jest-diff" "*" +"@types/lodash@^4.14.141": + version "4.14.141" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.141.tgz#d81f4d0c562abe28713406b571ffb27692a82ae6" + integrity sha512-v5NYIi9qEbFEUpCyikmnOYe4YlP8BMUdTcNCAquAKzu+FA7rZ1onj9x80mbnDdOW/K5bFf3Tv5kJplP33+gAbQ== + "@types/node@^12.0.2": version "12.0.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.2.tgz#3452a24edf9fea138b48fad4a0a028a683da1e40" @@ -2421,6 +2426,11 @@ lodash@^4.17.11: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== +lodash@^4.17.15: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"