@peabody-soft/mbs-model-ts 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/Attachment.js +2 -2
  2. package/dist/AttachmentBaseUrl.js +4 -4
  3. package/dist/AuthTokens.js +7 -7
  4. package/dist/Business.js +11 -10
  5. package/dist/BusinessIdentifier.js +3 -2
  6. package/dist/BusinessLink.js +3 -2
  7. package/dist/CartEditor.js +89 -81
  8. package/dist/Catalog.d.ts +19 -7
  9. package/dist/Catalog.js +121 -41
  10. package/dist/Constants.d.ts +1 -0
  11. package/dist/Constants.js +7 -5
  12. package/dist/ContainerNames.js +6 -6
  13. package/dist/Entity.js +4 -3
  14. package/dist/Enums.d.ts +1 -0
  15. package/dist/Enums.js +3 -2
  16. package/dist/Exceptions.js +2 -2
  17. package/dist/GeneralSettings.d.ts +5 -4
  18. package/dist/GeneralSettings.js +17 -15
  19. package/dist/HttpStatusCodes.js +7 -7
  20. package/dist/Ids.js +4 -5
  21. package/dist/Item.js +8 -5
  22. package/dist/LiveData.js +2 -2
  23. package/dist/Measures.js +3 -2
  24. package/dist/Message.js +1 -1
  25. package/dist/MockDatabase.js +6 -5
  26. package/dist/Model.js +166 -162
  27. package/dist/Order.js +10 -12
  28. package/dist/Package.d.ts +6 -2
  29. package/dist/Package.js +10 -5
  30. package/dist/PackageIdentifier.js +2 -2
  31. package/dist/Price.js +6 -5
  32. package/dist/PriceList.d.ts +13 -0
  33. package/dist/PriceList.js +34 -2
  34. package/dist/Product.d.ts +6 -2
  35. package/dist/Product.js +15 -10
  36. package/dist/Profile.js +15 -14
  37. package/dist/ProtoMap.js +189 -206
  38. package/dist/ServiceExceptions.js +6 -6
  39. package/dist/ServiceProxy.js +15 -14
  40. package/dist/ShoppingList.js +102 -100
  41. package/dist/SyncCache.js +76 -68
  42. package/dist/SyncKeys.js +5 -5
  43. package/dist/SyncState.js +14 -6
  44. package/dist/Tax.js +11 -10
  45. package/dist/TaxHelper.js +9 -8
  46. package/dist/TaxType.js +7 -6
  47. package/dist/UserProfile.js +7 -7
  48. package/dist/WorkingDays.js +21 -18
  49. package/dist/generated/BusinessSyncOutResponse.d.ts +4 -1
  50. package/dist/generated/Constants.d.ts +0 -4
  51. package/dist/generated/Constants.js +0 -4
  52. package/dist/generated/GeneralSettings.d.ts +5 -4
  53. package/dist/generated/GeneralSettings.js +8 -6
  54. package/dist/generated/Item.d.ts +4 -3
  55. package/dist/generated/Message.d.ts +5 -0
  56. package/dist/generated/OnlineStoreTheme.d.ts +33 -0
  57. package/dist/generated/OnlineStoreTheme.js +38 -0
  58. package/dist/generated/PriceList.d.ts +3 -2
  59. package/dist/generated/ProfileSyncOutRequest.d.ts +16 -15
  60. package/dist/generated/ProfileSyncOutResponse.d.ts +4 -6
  61. package/dist/generated/SalesOrderPayload.d.ts +6 -3
  62. package/dist/index.d.ts +4 -0
  63. package/dist/index.js +11 -8
  64. package/package.json +2 -2
package/dist/Order.js CHANGED
@@ -3,11 +3,9 @@ import { amountFromScaledValue } from "./Constants";
3
3
  import Message from "./Message";
4
4
  // An order a customer has placed: a message carrying a sales order payload.
5
5
  // The business completes an order (fulfilling or cancelling it) by deleting its message, so
6
- // isDeleted is true of a completed order. That message is still the whole order: status and what
7
- // the customer ordered are there to show, as for an open one. status says how far the business
8
- // got with it.
9
- // deliveryAddressId is an id into the customer's address list. deliveryAddress is a full address
10
- // sent directly, and takes precedence over deliveryAddressId when both are present.
6
+ // isDeleted is true of a completed order. The deleted message still holds the whole order, with
7
+ // its status and what the customer ordered, as an open order does. status records how far the
8
+ // business got with it.
11
9
  export default class Order extends Message {
12
10
  // For ProtoMap, which sees a total still multiplied by Constants.AMOUNT_FACTOR.
13
11
  static fromScaledValues(header, senderId, taskStatus, senderName, senderPhone, status, fulfillmentMode, shoppingList, scaledShoppingListTotal, shoppingListCount, deliveryAddressId, deliveryAddress, creationDate, note, scaledPaymentReceived) {
@@ -34,22 +32,22 @@ export default class Order extends Message {
34
32
  get fulfillmentMode() {
35
33
  return this._fulfillmentMode;
36
34
  }
37
- // What was ordered. An order completed before the business kept the list with it (an older
38
- // merchant app moved the list into a record of the sale, which a customer never sees) holds
39
- // ShoppingList.EMPTY, which has no lines. The totals below are then all that is left.
35
+ // What was ordered. An older merchant app moved the list of a completed order into a record of
36
+ // the sale, which a customer never sees. Such an order holds ShoppingList.EMPTY, which has no
37
+ // lines, and only the totals below remain.
40
38
  get shoppingList() {
41
39
  return this._shoppingList;
42
40
  }
43
- // The authoritative total to display. Unlike a total read off the list, it survives the order
44
- // having no list.
41
+ // The authoritative total to display. Unlike a total computed from the list, it is still
42
+ // available when the order has no list.
45
43
  get shoppingListTotal() {
46
44
  return this._shoppingListTotal;
47
45
  }
48
46
  get shoppingListCount() {
49
47
  return this._shoppingListCount;
50
48
  }
51
- // Names an address in the customer's address list. Constants.ENTITY_ID_NULL when the order has no
52
- // delivery address, as is normal for a pickup.
49
+ // The id of an address in the customer's address list, or Constants.ENTITY_ID_NULL when the order
50
+ // names none, as is normal for a pickup.
53
51
  get deliveryAddressId() {
54
52
  return this._deliveryAddressId;
55
53
  }
package/dist/Package.d.ts CHANGED
@@ -11,8 +11,7 @@ export default class Package extends Item {
11
11
  private readonly _dimensions;
12
12
  private readonly _weight;
13
13
  private readonly _photos;
14
- private readonly _price;
15
- constructor(header: EntityHeader, name: string, description: string | null, productId: bigint, isDisabled: boolean, _isSoldLoose: boolean, _itemCode: bigint, _identifiers: ReadonlyArray<PackageIdentifier>, _dimensions: Dimensions | null, _weight: Weight | null, _photos: ReadonlyArray<Photo>, _price: Price | null);
14
+ constructor(header: EntityHeader, name: string, description: string | null, productId: bigint, isDisabled: boolean, _isSoldLoose: boolean, _itemCode: bigint, _identifiers: ReadonlyArray<PackageIdentifier>, _dimensions: Dimensions | null, _weight: Weight | null, _photos: ReadonlyArray<Photo>);
16
15
  get productId(): bigint;
17
16
  get isSoldLoose(): boolean;
18
17
  get itemCode(): bigint;
@@ -21,5 +20,10 @@ export default class Package extends Item {
21
20
  get weight(): Weight | null;
22
21
  get photos(): ReadonlyArray<Photo>;
23
22
  get price(): Price | null;
23
+ private set price(value);
24
24
  get isBuyable(): boolean;
25
+ private _price;
26
+ }
27
+ export interface UpdatablePackage {
28
+ set price(value: Price | null);
25
29
  }
package/dist/Package.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import Item from "./Item";
2
2
  // A package, or variant, of a product (a 500 gram bottle of mango pickle, say) and the thing a
3
- // customer buys. Built complete, with photos and price resolved, so everything here is readonly.
3
+ // customer buys. Built with its photos. Catalog sets the price, once the price list to sell from is
4
+ // known.
4
5
  export default class Package extends Item {
5
- constructor(header, name, description, productId, isDisabled, _isSoldLoose, _itemCode, _identifiers, _dimensions, _weight, _photos, _price) {
6
+ constructor(header, name, description, productId, isDisabled, _isSoldLoose, _itemCode, _identifiers, _dimensions, _weight, _photos) {
6
7
  super(header, name, description, productId, isDisabled);
7
8
  this._isSoldLoose = _isSoldLoose;
8
9
  this._itemCode = _itemCode;
@@ -10,7 +11,7 @@ export default class Package extends Item {
10
11
  this._dimensions = _dimensions;
11
12
  this._weight = _weight;
12
13
  this._photos = _photos;
13
- this._price = _price;
14
+ this._price = null;
14
15
  }
15
16
  // The product this package is a variant of, which is the parent id every item has
16
17
  get productId() {
@@ -37,11 +38,15 @@ export default class Package extends Item {
37
38
  get photos() {
38
39
  return this._photos;
39
40
  }
40
- // What this package costs, with the taxes of its product included (Product.taxes). Null when the
41
- // business has not priced it, so it cannot be bought.
41
+ // What this package costs, with the taxes of its product included (Product.taxes). It is the
42
+ // price in the catalog's sale price list, or in that list's parent. Null when neither has one, so
43
+ // the package cannot be bought.
42
44
  get price() {
43
45
  return this._price;
44
46
  }
47
+ set price(value) {
48
+ this._price = value;
49
+ }
45
50
  // True when this package is enabled and has an enabled price. Checked here because a
46
51
  // product-level filter does not guarantee that every package, or every price, of an otherwise
47
52
  // visible product is enabled.
@@ -1,5 +1,5 @@
1
- // An identifier of a package, such as a GTIN, and its kind. Java keys kinds by string id, so map
2
- // through the comments in PackageIdentifierType.proto, never the enum ordinal.
1
+ // An identifier of a package, such as a GTIN, and its kind. Java keys kinds by string id. Map a
2
+ // kind using the comments in PackageIdentifierType.proto, not the enum ordinal.
3
3
  export default class PackageIdentifier {
4
4
  constructor(_type, _value) {
5
5
  this._type = _type;
package/dist/Price.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import { amountFromScaledValue } from "./Constants";
2
2
  import Item from "./Item";
3
- // What one package costs: the regular price and the offer price. Exposed unscaled as numbers; they
4
- // travel multiplied by Constants.AMOUNT_FACTOR and stay well below 2^53, so nothing is lost.
3
+ // What one package costs: the regular price and the offer price. Both are exposed as unscaled
4
+ // numbers. On the wire they are multiplied by Constants.AMOUNT_FACTOR and stay well below 2^53,
5
+ // so unscaling loses nothing.
5
6
  //
6
- // BOTH INCLUDE TAXES: the taxes of the package's product (Product.taxes) are in the price, not
7
- // added to it, so this is what a customer pays and what a catalog shows. A shopping list stores a
8
- // price without them, so a cart takes the taxes out (CartEditor).
7
+ // BOTH INCLUDE TAXES: the taxes of the package's product (Product.taxes) are part of each price,
8
+ // not added to it, so a price is what a customer pays and what a catalog shows. A shopping list
9
+ // stores a price without taxes, so a cart takes them out (CartEditor).
9
10
  export default class Price extends Item {
10
11
  // For ProtoMap, which sees prices still multiplied by Constants.AMOUNT_FACTOR.
11
12
  static fromScaledValues(header, name, description, priceListId, isDisabled, packageId, scaledRegularPrice, scaledOfferPrice) {
@@ -1,3 +1,16 @@
1
1
  import Item from "./Item";
2
+ import Price from "./Price";
2
3
  export default class PriceList extends Item {
4
+ get parentPriceListId(): bigint;
5
+ get parentPriceList(): PriceList | null;
6
+ private set parentPriceList(value);
7
+ get prices(): ReadonlyMap<bigint, Price>;
8
+ private set prices(value);
9
+ getPrice(packageId: bigint): Price | null;
10
+ private _parentPriceList;
11
+ private _prices;
12
+ }
13
+ export interface UpdatablePriceList {
14
+ set parentPriceList(value: PriceList | null);
15
+ set prices(value: ReadonlyMap<bigint, Price>);
3
16
  }
package/dist/PriceList.js CHANGED
@@ -1,5 +1,37 @@
1
1
  import Item from "./Item";
2
- // A named list of prices. A storefront sells from one, so no package has two prices to choose
3
- // between. Carried as an object, not a bare id, because a client naming a cart needs it.
2
+ // A named list of prices, at most one per package. A list can have a parent, named by its
3
+ // parentItemId. A package with no price in the list is priced from the parent. Catalog sets the
4
+ // prices and the parent, once every price list and price has been read.
4
5
  export default class PriceList extends Item {
6
+ constructor() {
7
+ super(...arguments);
8
+ this._parentPriceList = null;
9
+ this._prices = new Map();
10
+ }
11
+ // The id of the list whose prices are used for the packages this list has no price for, or
12
+ // Constants.ENTITY_ID_NULL when this list has no parent
13
+ get parentPriceListId() {
14
+ return this.parentItemId;
15
+ }
16
+ // Null when this list has no parent, or when the parent was not read. Not Entity.parent, which is
17
+ // the business.
18
+ get parentPriceList() {
19
+ return this._parentPriceList;
20
+ }
21
+ set parentPriceList(value) {
22
+ this._parentPriceList = value;
23
+ }
24
+ // The prices of this list itself, by package id. getPrice also looks in the parent.
25
+ get prices() {
26
+ return this._prices;
27
+ }
28
+ set prices(value) {
29
+ this._prices = value;
30
+ }
31
+ // The price of a package: this list's own, else the parent's own, else null. Only the parent is
32
+ // consulted, not its parent. A price is returned even when disabled, so a package with a disabled
33
+ // price here is not priced from the parent.
34
+ getPrice(packageId) {
35
+ return this._prices.get(packageId) ?? this._parentPriceList?._prices.get(packageId) ?? null;
36
+ }
5
37
  }
package/dist/Product.d.ts CHANGED
@@ -16,7 +16,7 @@ export default class Product extends Item {
16
16
  private readonly _features;
17
17
  private readonly _isForOfflineSaleOnly;
18
18
  private readonly _photos;
19
- constructor(header: EntityHeader, name: string, description: string | null, productCategoryId: bigint, isDisabled: boolean, _productType: proto_ProductType, _brand: string | null, _isManufacturedByBusiness: boolean, _manufacturer: string | null, _manufacturerAddress: Address | null, _taxes: ReadonlyArray<Tax>, _features: ReadonlyArray<string>, _isForOfflineSaleOnly: boolean, _photos: ReadonlyArray<Photo>, packages: ReadonlyArray<Package>);
19
+ constructor(header: EntityHeader, name: string, description: string | null, productCategoryId: bigint, isDisabled: boolean, _productType: proto_ProductType, _brand: string | null, _isManufacturedByBusiness: boolean, _manufacturer: string | null, _manufacturerAddress: Address | null, _taxes: ReadonlyArray<Tax>, _features: ReadonlyArray<string>, _isForOfflineSaleOnly: boolean, _photos: ReadonlyArray<Photo>);
20
20
  get productCategoryId(): bigint;
21
21
  get productType(): proto_ProductType;
22
22
  get brand(): string | null;
@@ -28,8 +28,12 @@ export default class Product extends Item {
28
28
  get isForOfflineSaleOnly(): boolean;
29
29
  get photos(): ReadonlyArray<Photo>;
30
30
  get packages(): ReadonlyArray<Package>;
31
+ private set packages(value);
31
32
  get lowestPrice(): Price | null;
32
33
  get isOnOffer(): boolean;
33
34
  get isBuyable(): boolean;
34
- private readonly _packages;
35
+ private _packages;
36
+ }
37
+ export interface UpdatableProduct {
38
+ set packages(value: ReadonlyArray<Package>);
35
39
  }
package/dist/Product.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import Item from "./Item";
2
- // A product in the catalog: goods, a service, a raw material or a fixed asset. Built complete
3
- // (photos and packages resolved first), so everything here is readonly.
2
+ // A product in the catalog: goods, a service, a raw material or a fixed asset. Built with its
3
+ // photos. Catalog sets its packages, once their prices are known.
4
4
  export default class Product extends Item {
5
- constructor(header, name, description, productCategoryId, isDisabled, _productType, _brand, _isManufacturedByBusiness, _manufacturer, _manufacturerAddress, _taxes, _features, _isForOfflineSaleOnly, _photos, packages) {
5
+ constructor(header, name, description, productCategoryId, isDisabled, _productType, _brand, _isManufacturedByBusiness, _manufacturer, _manufacturerAddress, _taxes, _features, _isForOfflineSaleOnly, _photos) {
6
6
  super(header, name, description, productCategoryId, isDisabled);
7
7
  this._productType = _productType;
8
8
  this._brand = _brand;
@@ -13,8 +13,7 @@ export default class Product extends Item {
13
13
  this._features = _features;
14
14
  this._isForOfflineSaleOnly = _isForOfflineSaleOnly;
15
15
  this._photos = _photos;
16
- // A package that cannot be bought is not kept, whoever builds the product and whatever they pass in
17
- this._packages = Object.freeze(packages.filter((pkg) => pkg.isBuyable));
16
+ this._packages = Object.freeze([]);
18
17
  }
19
18
  // The category this product is in, or Constants.ENTITY_ID_NULL when it is in none
20
19
  get productCategoryId() {
@@ -38,11 +37,12 @@ export default class Product extends Item {
38
37
  return this._manufacturerAddress;
39
38
  }
40
39
  // The taxes included in the price of every package of this product (see Price), not added to it.
41
- // A UI shows a price as is, and shows these only as part of what a bill's total includes.
40
+ // A UI shows a price as is, and shows these taxes only as the portion of a bill's total that
41
+ // they make up.
42
42
  get taxes() {
43
43
  return this._taxes;
44
44
  }
45
- // One line bullet points about this product
45
+ // Bullet points about this product, one line each
46
46
  get features() {
47
47
  return this._features;
48
48
  }
@@ -60,21 +60,26 @@ export default class Product extends Item {
60
60
  get packages() {
61
61
  return this._packages;
62
62
  }
63
+ // Keeps the buyable packages among those given, and drops the rest
64
+ set packages(value) {
65
+ this._packages = Object.freeze(value.filter((pkg) => pkg.isBuyable));
66
+ }
63
67
  // The cheapest final price across variants (what a listing shows as "from"), or null if there
64
68
  // are no variants. Compares final price, since that is what a customer pays. Every variant is
65
- // taxed at this product's rates, so prices with taxes order the variants as prices without would.
69
+ // taxed at this product's rates, so comparing prices with taxes gives the same order as
70
+ // comparing them without.
66
71
  get lowestPrice() {
67
72
  let result = null;
68
73
  for (const pkg of this._packages) {
69
74
  const price = pkg.price;
70
75
  if (price === null)
71
- continue; // Not so of a buyable variant, though the type does not say
76
+ continue; // A buyable variant always has a price, but the type allows null
72
77
  if (result === null || price.finalPrice < result.finalPrice)
73
78
  result = price;
74
79
  }
75
80
  return result;
76
81
  }
77
- // True when any variant of this product is on offer, which is what a listing puts a badge on
82
+ // True when any variant of this product is on offer. A listing shows a badge for this.
78
83
  get isOnOffer() {
79
84
  for (const pkg of this._packages)
80
85
  if (pkg.price?.isOnOffer === true)
package/dist/Profile.js CHANGED
@@ -26,7 +26,7 @@ export default class Profile {
26
26
  this._businessLinkMap.set(businessLink.businessId, businessLink);
27
27
  }
28
28
  }
29
- // The id of the profile container this was built from, and what Model.signIn was given
29
+ // The subject id that Model.signIn was given, which the profile container's name is built from
30
30
  get profileId() {
31
31
  return this._profileId;
32
32
  }
@@ -51,8 +51,8 @@ export default class Profile {
51
51
  return this._businessLinkMap.get(businessEntityId) ?? null;
52
52
  }
53
53
  // The same, by the url friendly business id a storefront is reached by, however it is written in
54
- // the url. The server finds a business whatever the case, so this must too, or a customer who
55
- // has joined would be asked to join again.
54
+ // the url. The server finds a business whatever the case, so this must too. Otherwise a customer
55
+ // who has joined would be treated as not a member and asked to join again.
56
56
  getBusinessLinkFor(businessId) {
57
57
  const wanted = canonicalizeBusinessId(businessId);
58
58
  for (const business of this._businesses)
@@ -68,15 +68,16 @@ export default class Profile {
68
68
  // spaces normalized as Java StringHelper.normalizeSpace does, then lower case. So a url typed in any
69
69
  // case or spacing names one business. Inner spaces count, as an id can hold some (Java builds one
70
70
  // from the display name, "Warm Loaf_1a2b3c4d", or takes what is typed).
71
- // normalizeSpace is followed step for step, quirks included: a string with no whitespace at either
72
- // end and none twice in a row is left alone, and a non-breaking space is not whitespace to it, so
73
- // one between words stays unless something else in the string is normalized.
74
- // Java refuses an id not four to sixty-four characters long. This is only a comparison and does
75
- // not. The server answers a read of such an id with NotFoundException, as for a missing business.
71
+ // This follows normalizeSpace step for step, quirks included. A string with no whitespace at either
72
+ // end and none twice in a row is returned unchanged. A non-breaking space does not count as
73
+ // whitespace, but it becomes a plain space if the string is normalized for another reason.
74
+ // Java rejects an id that is not four to sixty-four characters long. This function only normalizes
75
+ // for comparison and does not check the length. The server answers a read of such an id with
76
+ // NotFoundException, as for a missing business.
76
77
  export function canonicalizeBusinessId(businessId) {
77
78
  return normalizeSpace(businessId).toLowerCase();
78
79
  }
79
- // Java StringHelper.normalizeSpace. Where Java answers null (a string of only whitespace), this answers an empty string.
80
+ // Java StringHelper.normalizeSpace. Where Java returns null (a string of only whitespace), this returns an empty string.
80
81
  function normalizeSpace(input) {
81
82
  if (!needsNormalization(input))
82
83
  return input;
@@ -98,8 +99,8 @@ function normalizeSpace(input) {
98
99
  }
99
100
  if (isAtStart)
100
101
  return "";
101
- // Java String.trim removes every character up to a space from either end, unlike a script's trim, which removes
102
- // Unicode spaces. The space standing for trailing whitespace goes with it (Java drops that one first, same result)
102
+ // Java String.trim removes every character up to a space from either end, unlike JavaScript's trim, which removes
103
+ // Unicode whitespace. The trailing space added for trailing whitespace is trimmed too (Java drops it first, with the same result)
103
104
  let first = 0;
104
105
  let last = result.length;
105
106
  while (first < last && result.charCodeAt(first) <= SPACE)
@@ -108,7 +109,7 @@ function normalizeSpace(input) {
108
109
  --last;
109
110
  return result.slice(first, last);
110
111
  }
111
- // Java StringHelper.needsNormalization: whitespace at either end, or two together between
112
+ // Java StringHelper.needsNormalization: whitespace at either end, or two whitespace characters in a row inside
112
113
  function needsNormalization(input) {
113
114
  if (input.length === 0)
114
115
  return false;
@@ -123,8 +124,8 @@ function needsNormalization(input) {
123
124
  }
124
125
  return false;
125
126
  }
126
- // Java Character.isWhitespace: the Unicode spaces that do not hold a place (not the no-break ones U+00A0, U+2007 and
127
- // U+202F) and the control characters that are spaces. A regular expression's \s differs: it includes the no-break
127
+ // Java Character.isWhitespace: the Unicode separators except the no-break ones (U+00A0, U+2007 and U+202F),
128
+ // and the control characters that are whitespace. A regular expression's \s differs: it includes the no-break
128
129
  // spaces and the byte order mark, and excludes U+001C to U+001F
129
130
  function isWhitespace(unit) {
130
131
  if (unit === SPACE)