standin_order.ts
1 import type { CodecKey, CodecValue } from "@massmarket/utils/codec"; 2 3 import { ChainAddress, Payee } from "./standin_manifest.ts"; 4 import { 5 BaseClass, 6 ensureDate, 7 ensureNumber, 8 ensureSomeNumberAsBigInt, 9 ensureString, 10 ensureStringArray, 11 ensureUint8Array, 12 } from "./utils.ts"; 13 14 export class Order extends BaseClass { 15 ID: number; 16 Items: OrderedItem[]; 17 State: OrderState; 18 InvoiceAddress?: AddressDetails; 19 ShippingAddress?: AddressDetails; 20 CanceledAt?: Date; 21 ChosenPayee?: Payee; 22 ChosenCurrency?: ChainAddress; 23 PaymentDetails?: PaymentDetails; 24 TxDetails?: OrderPaid; 25 26 constructor( 27 id: number = 0, 28 items: OrderedItem[] = [], 29 state: OrderState = OrderState.Unspecified, 30 invoiceAddress?: AddressDetails, 31 shippingAddress?: AddressDetails, 32 canceledAt?: Date, 33 chosenPayee?: Payee, 34 chosenCurrency?: ChainAddress, 35 paymentDetails?: PaymentDetails, 36 txDetails?: OrderPaid, 37 ) { 38 super(); 39 this.ID = id; 40 this.Items = items; 41 this.State = state; 42 this.InvoiceAddress = invoiceAddress; 43 this.ShippingAddress = shippingAddress; 44 this.CanceledAt = canceledAt; 45 this.ChosenPayee = chosenPayee; 46 this.ChosenCurrency = chosenCurrency; 47 this.PaymentDetails = paymentDetails; 48 this.TxDetails = txDetails; 49 } 50 51 static fromCBOR(value: CodecValue): Order { 52 if (!(value instanceof Map)) { 53 throw new TypeError("Expected value to be a Map"); 54 } 55 const input = value as Map<CodecKey, CodecValue>; 56 const id = ensureNumber(input.get("ID"), "ID"); 57 58 const items: OrderedItem[] = []; 59 const itemsData = input.get("Items"); 60 if (itemsData !== undefined) { 61 if (!Array.isArray(itemsData)) { 62 throw new TypeError("Expected Items to be an array"); 63 } 64 items.push(...itemsData.map((item) => { 65 if (!(item instanceof Map)) { 66 throw new TypeError("Expected item to be a Map"); 67 } 68 return OrderedItem.fromCBOR(item); 69 })); 70 } 71 72 const stateNum = ensureNumber(input.get("State"), "State"); 73 74 let invoiceAddress: AddressDetails | undefined; 75 const invoiceAddressData = input.get("InvoiceAddress"); 76 if (invoiceAddressData !== undefined) { 77 if (!(invoiceAddressData instanceof Map)) { 78 throw new TypeError("Expected InvoiceAddress to be a Map"); 79 } 80 invoiceAddress = AddressDetails.fromCBOR(invoiceAddressData); 81 } 82 83 let shippingAddress: AddressDetails | undefined; 84 const shippingAddressData = input.get("ShippingAddress"); 85 if (shippingAddressData !== undefined) { 86 if (!(shippingAddressData instanceof Map)) { 87 throw new TypeError("Expected ShippingAddress to be a Map"); 88 } 89 shippingAddress = AddressDetails.fromCBOR(shippingAddressData); 90 } 91 92 let canceledAt: Date | undefined; 93 const canceledAtData = input.get("CanceledAt"); 94 if (canceledAtData !== undefined) { 95 canceledAt = ensureDate(canceledAtData, "CanceledAt"); 96 } 97 98 let chosenPayee: Payee | undefined; 99 const chosenPayeeData = input.get("ChosenPayee"); 100 if (chosenPayeeData !== undefined) { 101 if (!(chosenPayeeData instanceof Map)) { 102 throw new TypeError("Expected ChosenPayee to be a Map"); 103 } 104 chosenPayee = Payee.fromCBOR(chosenPayeeData); 105 } 106 107 let chosenCurrency: ChainAddress | undefined; 108 const chosenCurrencyData = input.get("ChosenCurrency"); 109 if (chosenCurrencyData !== undefined) { 110 if (!(chosenCurrencyData instanceof Map)) { 111 throw new TypeError("Expected ChosenCurrency to be a Map"); 112 } 113 chosenCurrency = ChainAddress.fromCBOR(chosenCurrencyData); 114 } 115 116 let paymentDetails: PaymentDetails | undefined; 117 const paymentDetailsData = input.get("PaymentDetails"); 118 if (paymentDetailsData !== undefined) { 119 if (!(paymentDetailsData instanceof Map)) { 120 throw new TypeError("Expected PaymentDetails to be a Map"); 121 } 122 paymentDetails = PaymentDetails.fromCBOR(paymentDetailsData); 123 } 124 125 let txDetails: OrderPaid | undefined; 126 const txDetailsData = input.get("TxDetails"); 127 if (txDetailsData !== undefined) { 128 if (!(txDetailsData instanceof Map)) { 129 throw new TypeError("Expected TxDetails to be a Map"); 130 } 131 txDetails = OrderPaid.fromCBOR(txDetailsData); 132 } 133 134 return new Order( 135 id, 136 items, 137 stateNum, 138 invoiceAddress, 139 shippingAddress, 140 canceledAt, 141 chosenPayee, 142 chosenCurrency, 143 paymentDetails, 144 txDetails, 145 ); 146 } 147 } 148 149 export class OrderedItem extends BaseClass { 150 ListingID: number; 151 VariationIDs?: string[]; 152 Quantity: number; 153 154 constructor( 155 listingID: number = 0, 156 quantity: number = 1, 157 variationIDs?: string[], 158 ) { 159 super(); 160 this.ListingID = listingID; 161 this.Quantity = quantity; 162 this.VariationIDs = variationIDs; 163 } 164 165 static fromCBOR(value: CodecValue): OrderedItem { 166 if (!(value instanceof Map)) { 167 throw new TypeError("Expected value to be a Map"); 168 } 169 const input = value as Map<CodecKey, CodecValue>; 170 const listingID = ensureNumber(input.get("ListingID"), "ListingID"); 171 const quantity = ensureNumber(input.get("Quantity"), "Quantity"); 172 173 let variationIDs: string[] | undefined; 174 const variationIDsData = input.get("VariationIDs"); 175 if (variationIDsData !== undefined) { 176 variationIDs = ensureStringArray(variationIDsData, "VariationIDs"); 177 } 178 179 return new OrderedItem(listingID, quantity, variationIDs); 180 } 181 } 182 183 export enum OrderState { 184 Unspecified = 0, 185 Open = 1, 186 Canceled = 2, 187 Committed = 3, 188 PaymentChosen = 4, 189 Unpaid = 5, 190 Paid = 6, 191 } 192 193 export class AddressDetails extends BaseClass { 194 Name: string; 195 Address1: string; 196 Address2?: string; 197 City: string; 198 PostalCode: string; 199 Country: string; 200 EmailAddress: string; 201 PhoneNumber?: string; 202 203 constructor( 204 name: string = "", 205 address1: string = "", 206 city: string = "", 207 postalCode: string = "", 208 country: string = "", 209 emailAddress: string = "", 210 address2?: string, 211 phoneNumber?: string, 212 ) { 213 super(); 214 this.Name = name; 215 this.Address1 = address1; 216 this.Address2 = address2; 217 this.City = city; 218 this.PostalCode = postalCode; 219 this.Country = country; 220 this.EmailAddress = emailAddress; 221 this.PhoneNumber = phoneNumber; 222 } 223 224 static fromCBOR(value: CodecValue): AddressDetails { 225 if (!(value instanceof Map)) { 226 throw new TypeError("Expected value to be a Map"); 227 } 228 const input = value as Map<CodecKey, CodecValue>; 229 const name = ensureString(input.get("Name"), "Name"); 230 const address1 = ensureString(input.get("Address1"), "Address1"); 231 const city = ensureString(input.get("City"), "City"); 232 const postalCode = ensureString(input.get("PostalCode"), "PostalCode"); 233 const country = ensureString(input.get("Country"), "Country"); 234 const emailAddress = ensureString( 235 input.get("EmailAddress"), 236 "EmailAddress", 237 ); 238 239 let address2: string | undefined; 240 const address2Data = input.get("Address2"); 241 if (address2Data !== undefined) { 242 address2 = ensureString(address2Data, "Address2"); 243 } 244 245 let phoneNumber: string | undefined; 246 const phoneNumberData = input.get("PhoneNumber"); 247 if (phoneNumberData !== undefined) { 248 phoneNumber = ensureString(phoneNumberData, "PhoneNumber"); 249 } 250 251 return new AddressDetails( 252 name, 253 address1, 254 city, 255 postalCode, 256 country, 257 emailAddress, 258 address2, 259 phoneNumber, 260 ); 261 } 262 } 263 264 export class PaymentDetails extends BaseClass { 265 PaymentID: Uint8Array; 266 Total: bigint | number; 267 ListingHashes: Uint8Array[]; 268 TTL: number; 269 ShopSignature: Uint8Array; 270 271 constructor( 272 paymentID: Uint8Array = new Uint8Array(32), 273 total: bigint | number = 0n, 274 ttl: number = 0, 275 shopSignature: Uint8Array = new Uint8Array(65), 276 listingHashes: Uint8Array[] = [], 277 ) { 278 super(); 279 this.PaymentID = paymentID; 280 this.Total = total; 281 this.ListingHashes = listingHashes; 282 this.TTL = ttl; 283 this.ShopSignature = shopSignature; 284 } 285 286 static fromCBOR(value: CodecValue): PaymentDetails { 287 if (!(value instanceof Map)) { 288 throw new TypeError("Expected value to be a Map"); 289 } 290 const input = value as Map<CodecKey, CodecValue>; 291 const paymentID = ensureUint8Array(input.get("PaymentID"), "PaymentID", 32); 292 const total = ensureSomeNumberAsBigInt(input.get("Total"), "Total"); 293 const ttl = ensureNumber(input.get("TTL"), "TTL"); 294 const shopSignature = ensureUint8Array( 295 input.get("ShopSignature"), 296 "ShopSignature", 297 65, 298 ); 299 300 const listingHashes: Uint8Array[] = []; 301 const listingHashesData = input.get("ListingHashes"); 302 if (listingHashesData !== undefined) { 303 if (!Array.isArray(listingHashesData)) { 304 throw new TypeError("Expected ListingHashes to be an array"); 305 } 306 for (const [index, hash] of listingHashesData.entries()) { 307 if (!(hash instanceof Uint8Array)) { 308 throw new TypeError("Expected hash to be a Uint8Array"); 309 } 310 listingHashes.push(ensureUint8Array(hash, `hash ${index}`, 32)); 311 } 312 } 313 314 return new PaymentDetails( 315 paymentID, 316 total, 317 ttl, 318 shopSignature, 319 listingHashes, 320 ); 321 } 322 } 323 324 export class OrderPaid extends BaseClass { 325 TxHash?: Uint8Array; 326 BlockHash: Uint8Array; 327 328 constructor(blockHash: Uint8Array = new Uint8Array(32), txHash?: Uint8Array) { 329 super(); 330 this.BlockHash = blockHash; 331 this.TxHash = txHash; 332 } 333 334 static fromCBOR(value: CodecValue): OrderPaid { 335 if (!(value instanceof Map)) { 336 throw new TypeError("Expected value to be a Map"); 337 } 338 const input = value as Map<CodecKey, CodecValue>; 339 const blockHash = ensureUint8Array(input.get("BlockHash"), "BlockHash", 32); 340 341 let txHash: Uint8Array | undefined; 342 const txHashData = input.get("TxHash"); 343 if (txHashData !== undefined) { 344 txHash = ensureUint8Array(txHashData, "TxHash", 32); 345 } 346 347 return new OrderPaid(blockHash, txHash); 348 } 349 }