@blackcode_sa/metaestetics-api 1.12.32 → 1.12.33
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.
- package/dist/admin/index.d.mts +68 -21
- package/dist/admin/index.d.ts +68 -21
- package/dist/admin/index.js +35 -5
- package/dist/admin/index.mjs +35 -5
- package/dist/index.d.mts +169 -22
- package/dist/index.d.ts +169 -22
- package/dist/index.js +2602 -1771
- package/dist/index.mjs +1823 -992
- package/package.json +1 -1
- package/src/admin/booking/booking.admin.ts +40 -4
- package/src/services/appointment/appointment.service.ts +278 -0
- package/src/services/appointment/utils/extended-procedure.utils.ts +232 -0
- package/src/services/appointment/utils/zone-management.utils.ts +335 -0
- package/src/services/patient/patient.service.ts +46 -0
- package/src/services/procedure/procedure.service.ts +54 -0
- package/src/types/appointment/index.ts +75 -26
- package/src/validations/appointment.schema.ts +100 -4
package/dist/admin/index.d.mts
CHANGED
|
@@ -1627,8 +1627,12 @@ interface ProcedureExtendedInfo {
|
|
|
1627
1627
|
procedureTechnologyName: string;
|
|
1628
1628
|
procedureProductBrandId: string;
|
|
1629
1629
|
procedureProductBrandName: string;
|
|
1630
|
-
|
|
1631
|
-
|
|
1630
|
+
procedureProducts: Array<{
|
|
1631
|
+
productId: string;
|
|
1632
|
+
productName: string;
|
|
1633
|
+
brandId: string;
|
|
1634
|
+
brandName: string;
|
|
1635
|
+
}>;
|
|
1632
1636
|
}
|
|
1633
1637
|
/**
|
|
1634
1638
|
* Interface to describe a filled form linked to an appointment.
|
|
@@ -1668,26 +1672,38 @@ interface BeforeAfterPerZone {
|
|
|
1668
1672
|
beforeNote?: string | null;
|
|
1669
1673
|
}
|
|
1670
1674
|
/**
|
|
1671
|
-
* Interface for
|
|
1675
|
+
* Interface for zone item data (products or notes per zone)
|
|
1676
|
+
*/
|
|
1677
|
+
interface ZoneItemData {
|
|
1678
|
+
productId?: string;
|
|
1679
|
+
productName?: string;
|
|
1680
|
+
productBrandId?: string;
|
|
1681
|
+
productBrandName?: string;
|
|
1682
|
+
belongingProcedureId: string;
|
|
1683
|
+
type: 'item' | 'note';
|
|
1684
|
+
price?: number;
|
|
1685
|
+
currency?: Currency;
|
|
1686
|
+
unitOfMeasurement?: PricingMeasure;
|
|
1687
|
+
priceOverrideAmount?: number;
|
|
1688
|
+
quantity?: number;
|
|
1689
|
+
parentZone: string;
|
|
1690
|
+
subzones: string[];
|
|
1691
|
+
notes?: string;
|
|
1692
|
+
subtotal?: number;
|
|
1693
|
+
ionNumber?: string;
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* @deprecated Use ZoneItemData instead
|
|
1672
1697
|
*/
|
|
1673
1698
|
interface BillingPerZone {
|
|
1674
|
-
/** Product name/description */
|
|
1675
1699
|
Product: string;
|
|
1676
|
-
/** Product ID */
|
|
1677
1700
|
ProductId: string | null;
|
|
1678
|
-
/** Quantity used (can be decimal) */
|
|
1679
1701
|
Quantity: number;
|
|
1680
|
-
/** Unit of measurement */
|
|
1681
1702
|
UnitOfMeasurement: PricingMeasure;
|
|
1682
|
-
/** Unit price for the product */
|
|
1683
1703
|
UnitPrice: number;
|
|
1684
|
-
/** Currency for the unit price */
|
|
1685
1704
|
UnitCurency: Currency;
|
|
1686
|
-
/** Calculated subtotal */
|
|
1687
1705
|
Subtotal: number;
|
|
1688
|
-
/** Optional billing note */
|
|
1689
1706
|
Note: string | null;
|
|
1690
|
-
/** Ion/Batch number for traceability */
|
|
1691
1707
|
IonNumber: string | null;
|
|
1692
1708
|
}
|
|
1693
1709
|
/**
|
|
@@ -1702,27 +1718,57 @@ interface FinalBilling {
|
|
|
1702
1718
|
taxPrice: number;
|
|
1703
1719
|
/** Final price including tax */
|
|
1704
1720
|
finalPrice: number;
|
|
1705
|
-
/** Total final quantity across all zones */
|
|
1706
|
-
finalQuantity: number;
|
|
1707
1721
|
/** Currency for the final billing */
|
|
1708
1722
|
currency: Currency;
|
|
1709
|
-
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Interface for product metadata in appointment
|
|
1726
|
+
*/
|
|
1727
|
+
interface AppointmentProductMetadata {
|
|
1728
|
+
productId: string;
|
|
1729
|
+
productName: string;
|
|
1730
|
+
brandId: string;
|
|
1731
|
+
brandName: string;
|
|
1732
|
+
procedureId: string;
|
|
1733
|
+
price: number;
|
|
1734
|
+
currency: Currency;
|
|
1710
1735
|
unitOfMeasurement: PricingMeasure;
|
|
1711
1736
|
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Interface for extended procedures in appointment
|
|
1739
|
+
*/
|
|
1740
|
+
interface ExtendedProcedureInfo {
|
|
1741
|
+
procedureId: string;
|
|
1742
|
+
procedureName: string;
|
|
1743
|
+
procedureFamily?: ProcedureFamily;
|
|
1744
|
+
procedureCategoryId: string;
|
|
1745
|
+
procedureCategoryName: string;
|
|
1746
|
+
procedureSubCategoryId: string;
|
|
1747
|
+
procedureSubCategoryName: string;
|
|
1748
|
+
procedureTechnologyId: string;
|
|
1749
|
+
procedureTechnologyName: string;
|
|
1750
|
+
procedureProducts: Array<{
|
|
1751
|
+
productId: string;
|
|
1752
|
+
productName: string;
|
|
1753
|
+
brandId: string;
|
|
1754
|
+
brandName: string;
|
|
1755
|
+
}>;
|
|
1756
|
+
}
|
|
1712
1757
|
/**
|
|
1713
1758
|
* Interface for appointment metadata containing zone-specific information
|
|
1714
1759
|
*/
|
|
1715
1760
|
interface AppointmentMetadata {
|
|
1716
|
-
/** Array of selected zones for the appointment */
|
|
1717
1761
|
selectedZones: string[] | null;
|
|
1718
|
-
/** Map of zone photos with before/after images and notes */
|
|
1719
1762
|
zonePhotos: Record<string, BeforeAfterPerZone> | null;
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1763
|
+
zonesData?: Record<string, ZoneItemData[]> | null;
|
|
1764
|
+
appointmentProducts?: AppointmentProductMetadata[];
|
|
1765
|
+
extendedProcedures?: ExtendedProcedureInfo[];
|
|
1723
1766
|
finalbilling: FinalBilling | null;
|
|
1724
|
-
/** Final note for the appointment */
|
|
1725
1767
|
finalizationNotes: string | null;
|
|
1768
|
+
/**
|
|
1769
|
+
* @deprecated Use zonesData instead
|
|
1770
|
+
*/
|
|
1771
|
+
zoneBilling?: Record<string, BillingPerZone> | null;
|
|
1726
1772
|
}
|
|
1727
1773
|
/**
|
|
1728
1774
|
* Represents a booked appointment, aggregating key information and relevant procedure rules.
|
|
@@ -3324,6 +3370,7 @@ declare class BookingAdmin {
|
|
|
3324
3370
|
}>;
|
|
3325
3371
|
private _generateProcedureSummaryInfo;
|
|
3326
3372
|
private _generateProcedureExtendedInfo;
|
|
3373
|
+
private _generateAppointmentProductsFromProcedure;
|
|
3327
3374
|
}
|
|
3328
3375
|
|
|
3329
3376
|
/**
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -1627,8 +1627,12 @@ interface ProcedureExtendedInfo {
|
|
|
1627
1627
|
procedureTechnologyName: string;
|
|
1628
1628
|
procedureProductBrandId: string;
|
|
1629
1629
|
procedureProductBrandName: string;
|
|
1630
|
-
|
|
1631
|
-
|
|
1630
|
+
procedureProducts: Array<{
|
|
1631
|
+
productId: string;
|
|
1632
|
+
productName: string;
|
|
1633
|
+
brandId: string;
|
|
1634
|
+
brandName: string;
|
|
1635
|
+
}>;
|
|
1632
1636
|
}
|
|
1633
1637
|
/**
|
|
1634
1638
|
* Interface to describe a filled form linked to an appointment.
|
|
@@ -1668,26 +1672,38 @@ interface BeforeAfterPerZone {
|
|
|
1668
1672
|
beforeNote?: string | null;
|
|
1669
1673
|
}
|
|
1670
1674
|
/**
|
|
1671
|
-
* Interface for
|
|
1675
|
+
* Interface for zone item data (products or notes per zone)
|
|
1676
|
+
*/
|
|
1677
|
+
interface ZoneItemData {
|
|
1678
|
+
productId?: string;
|
|
1679
|
+
productName?: string;
|
|
1680
|
+
productBrandId?: string;
|
|
1681
|
+
productBrandName?: string;
|
|
1682
|
+
belongingProcedureId: string;
|
|
1683
|
+
type: 'item' | 'note';
|
|
1684
|
+
price?: number;
|
|
1685
|
+
currency?: Currency;
|
|
1686
|
+
unitOfMeasurement?: PricingMeasure;
|
|
1687
|
+
priceOverrideAmount?: number;
|
|
1688
|
+
quantity?: number;
|
|
1689
|
+
parentZone: string;
|
|
1690
|
+
subzones: string[];
|
|
1691
|
+
notes?: string;
|
|
1692
|
+
subtotal?: number;
|
|
1693
|
+
ionNumber?: string;
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* @deprecated Use ZoneItemData instead
|
|
1672
1697
|
*/
|
|
1673
1698
|
interface BillingPerZone {
|
|
1674
|
-
/** Product name/description */
|
|
1675
1699
|
Product: string;
|
|
1676
|
-
/** Product ID */
|
|
1677
1700
|
ProductId: string | null;
|
|
1678
|
-
/** Quantity used (can be decimal) */
|
|
1679
1701
|
Quantity: number;
|
|
1680
|
-
/** Unit of measurement */
|
|
1681
1702
|
UnitOfMeasurement: PricingMeasure;
|
|
1682
|
-
/** Unit price for the product */
|
|
1683
1703
|
UnitPrice: number;
|
|
1684
|
-
/** Currency for the unit price */
|
|
1685
1704
|
UnitCurency: Currency;
|
|
1686
|
-
/** Calculated subtotal */
|
|
1687
1705
|
Subtotal: number;
|
|
1688
|
-
/** Optional billing note */
|
|
1689
1706
|
Note: string | null;
|
|
1690
|
-
/** Ion/Batch number for traceability */
|
|
1691
1707
|
IonNumber: string | null;
|
|
1692
1708
|
}
|
|
1693
1709
|
/**
|
|
@@ -1702,27 +1718,57 @@ interface FinalBilling {
|
|
|
1702
1718
|
taxPrice: number;
|
|
1703
1719
|
/** Final price including tax */
|
|
1704
1720
|
finalPrice: number;
|
|
1705
|
-
/** Total final quantity across all zones */
|
|
1706
|
-
finalQuantity: number;
|
|
1707
1721
|
/** Currency for the final billing */
|
|
1708
1722
|
currency: Currency;
|
|
1709
|
-
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Interface for product metadata in appointment
|
|
1726
|
+
*/
|
|
1727
|
+
interface AppointmentProductMetadata {
|
|
1728
|
+
productId: string;
|
|
1729
|
+
productName: string;
|
|
1730
|
+
brandId: string;
|
|
1731
|
+
brandName: string;
|
|
1732
|
+
procedureId: string;
|
|
1733
|
+
price: number;
|
|
1734
|
+
currency: Currency;
|
|
1710
1735
|
unitOfMeasurement: PricingMeasure;
|
|
1711
1736
|
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Interface for extended procedures in appointment
|
|
1739
|
+
*/
|
|
1740
|
+
interface ExtendedProcedureInfo {
|
|
1741
|
+
procedureId: string;
|
|
1742
|
+
procedureName: string;
|
|
1743
|
+
procedureFamily?: ProcedureFamily;
|
|
1744
|
+
procedureCategoryId: string;
|
|
1745
|
+
procedureCategoryName: string;
|
|
1746
|
+
procedureSubCategoryId: string;
|
|
1747
|
+
procedureSubCategoryName: string;
|
|
1748
|
+
procedureTechnologyId: string;
|
|
1749
|
+
procedureTechnologyName: string;
|
|
1750
|
+
procedureProducts: Array<{
|
|
1751
|
+
productId: string;
|
|
1752
|
+
productName: string;
|
|
1753
|
+
brandId: string;
|
|
1754
|
+
brandName: string;
|
|
1755
|
+
}>;
|
|
1756
|
+
}
|
|
1712
1757
|
/**
|
|
1713
1758
|
* Interface for appointment metadata containing zone-specific information
|
|
1714
1759
|
*/
|
|
1715
1760
|
interface AppointmentMetadata {
|
|
1716
|
-
/** Array of selected zones for the appointment */
|
|
1717
1761
|
selectedZones: string[] | null;
|
|
1718
|
-
/** Map of zone photos with before/after images and notes */
|
|
1719
1762
|
zonePhotos: Record<string, BeforeAfterPerZone> | null;
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1763
|
+
zonesData?: Record<string, ZoneItemData[]> | null;
|
|
1764
|
+
appointmentProducts?: AppointmentProductMetadata[];
|
|
1765
|
+
extendedProcedures?: ExtendedProcedureInfo[];
|
|
1723
1766
|
finalbilling: FinalBilling | null;
|
|
1724
|
-
/** Final note for the appointment */
|
|
1725
1767
|
finalizationNotes: string | null;
|
|
1768
|
+
/**
|
|
1769
|
+
* @deprecated Use zonesData instead
|
|
1770
|
+
*/
|
|
1771
|
+
zoneBilling?: Record<string, BillingPerZone> | null;
|
|
1726
1772
|
}
|
|
1727
1773
|
/**
|
|
1728
1774
|
* Represents a booked appointment, aggregating key information and relevant procedure rules.
|
|
@@ -3324,6 +3370,7 @@ declare class BookingAdmin {
|
|
|
3324
3370
|
}>;
|
|
3325
3371
|
private _generateProcedureSummaryInfo;
|
|
3326
3372
|
private _generateProcedureExtendedInfo;
|
|
3373
|
+
private _generateAppointmentProductsFromProcedure;
|
|
3327
3374
|
}
|
|
3328
3375
|
|
|
3329
3376
|
/**
|
package/dist/admin/index.js
CHANGED
|
@@ -7662,6 +7662,7 @@ var BookingAdmin = class {
|
|
|
7662
7662
|
pendingUserFormTemplateIds = formInitResult.pendingUserFormsIds;
|
|
7663
7663
|
allLinkedFormTemplateIds = formInitResult.allLinkedTemplateIds;
|
|
7664
7664
|
}
|
|
7665
|
+
const appointmentProducts = this._generateAppointmentProductsFromProcedure(procedure);
|
|
7665
7666
|
const newAppointmentData = {
|
|
7666
7667
|
id: newAppointmentId,
|
|
7667
7668
|
calendarEventId: practitionerCalendarEventId,
|
|
@@ -7699,6 +7700,15 @@ var BookingAdmin = class {
|
|
|
7699
7700
|
linkedForms: initializedFormsInfo,
|
|
7700
7701
|
media: [],
|
|
7701
7702
|
reviewInfo: null,
|
|
7703
|
+
metadata: {
|
|
7704
|
+
selectedZones: null,
|
|
7705
|
+
zonePhotos: null,
|
|
7706
|
+
zonesData: null,
|
|
7707
|
+
appointmentProducts,
|
|
7708
|
+
extendedProcedures: [],
|
|
7709
|
+
finalbilling: null,
|
|
7710
|
+
finalizationNotes: null
|
|
7711
|
+
},
|
|
7702
7712
|
finalizedDetails: {
|
|
7703
7713
|
by: "",
|
|
7704
7714
|
at: adminTsNow,
|
|
@@ -7768,11 +7778,11 @@ var BookingAdmin = class {
|
|
|
7768
7778
|
};
|
|
7769
7779
|
}
|
|
7770
7780
|
_generateProcedureExtendedInfo(procedure) {
|
|
7771
|
-
var _a, _b;
|
|
7772
7781
|
const procedureCategory = procedure.category;
|
|
7773
7782
|
const procedureSubCategory = procedure.subcategory;
|
|
7774
7783
|
const procedureTechnology = procedure.technology;
|
|
7775
7784
|
const procedureProduct = procedure.product;
|
|
7785
|
+
const productsMetadata = procedure.productsMetadata || [];
|
|
7776
7786
|
return {
|
|
7777
7787
|
id: procedure.id,
|
|
7778
7788
|
name: procedure.name,
|
|
@@ -7786,12 +7796,32 @@ var BookingAdmin = class {
|
|
|
7786
7796
|
procedureSubCategoryName: (procedureSubCategory == null ? void 0 : procedureSubCategory.name) || "",
|
|
7787
7797
|
procedureTechnologyId: (procedureTechnology == null ? void 0 : procedureTechnology.id) || "",
|
|
7788
7798
|
procedureTechnologyName: (procedureTechnology == null ? void 0 : procedureTechnology.name) || "",
|
|
7789
|
-
procedureProductBrandId: (
|
|
7790
|
-
procedureProductBrandName: (
|
|
7791
|
-
|
|
7792
|
-
|
|
7799
|
+
procedureProductBrandId: (procedureProduct == null ? void 0 : procedureProduct.brandId) || "",
|
|
7800
|
+
procedureProductBrandName: (procedureProduct == null ? void 0 : procedureProduct.brandName) || "",
|
|
7801
|
+
procedureProducts: productsMetadata.map((pp) => ({
|
|
7802
|
+
productId: pp.product.id,
|
|
7803
|
+
productName: pp.product.name,
|
|
7804
|
+
brandId: pp.product.brandId,
|
|
7805
|
+
brandName: pp.product.brandName
|
|
7806
|
+
}))
|
|
7793
7807
|
};
|
|
7794
7808
|
}
|
|
7809
|
+
_generateAppointmentProductsFromProcedure(procedure) {
|
|
7810
|
+
const productsMetadata = procedure.productsMetadata || [];
|
|
7811
|
+
return productsMetadata.map((pp) => {
|
|
7812
|
+
const product = pp.product;
|
|
7813
|
+
return {
|
|
7814
|
+
productId: product.id,
|
|
7815
|
+
productName: product.name,
|
|
7816
|
+
brandId: product.brandId,
|
|
7817
|
+
brandName: product.brandName,
|
|
7818
|
+
procedureId: procedure.id,
|
|
7819
|
+
price: pp.price,
|
|
7820
|
+
currency: pp.currency,
|
|
7821
|
+
unitOfMeasurement: pp.pricingMeasure
|
|
7822
|
+
};
|
|
7823
|
+
});
|
|
7824
|
+
}
|
|
7795
7825
|
};
|
|
7796
7826
|
|
|
7797
7827
|
// src/admin/free-consultation/free-consultation-utils.admin.ts
|
package/dist/admin/index.mjs
CHANGED
|
@@ -7600,6 +7600,7 @@ var BookingAdmin = class {
|
|
|
7600
7600
|
pendingUserFormTemplateIds = formInitResult.pendingUserFormsIds;
|
|
7601
7601
|
allLinkedFormTemplateIds = formInitResult.allLinkedTemplateIds;
|
|
7602
7602
|
}
|
|
7603
|
+
const appointmentProducts = this._generateAppointmentProductsFromProcedure(procedure);
|
|
7603
7604
|
const newAppointmentData = {
|
|
7604
7605
|
id: newAppointmentId,
|
|
7605
7606
|
calendarEventId: practitionerCalendarEventId,
|
|
@@ -7637,6 +7638,15 @@ var BookingAdmin = class {
|
|
|
7637
7638
|
linkedForms: initializedFormsInfo,
|
|
7638
7639
|
media: [],
|
|
7639
7640
|
reviewInfo: null,
|
|
7641
|
+
metadata: {
|
|
7642
|
+
selectedZones: null,
|
|
7643
|
+
zonePhotos: null,
|
|
7644
|
+
zonesData: null,
|
|
7645
|
+
appointmentProducts,
|
|
7646
|
+
extendedProcedures: [],
|
|
7647
|
+
finalbilling: null,
|
|
7648
|
+
finalizationNotes: null
|
|
7649
|
+
},
|
|
7640
7650
|
finalizedDetails: {
|
|
7641
7651
|
by: "",
|
|
7642
7652
|
at: adminTsNow,
|
|
@@ -7706,11 +7716,11 @@ var BookingAdmin = class {
|
|
|
7706
7716
|
};
|
|
7707
7717
|
}
|
|
7708
7718
|
_generateProcedureExtendedInfo(procedure) {
|
|
7709
|
-
var _a, _b;
|
|
7710
7719
|
const procedureCategory = procedure.category;
|
|
7711
7720
|
const procedureSubCategory = procedure.subcategory;
|
|
7712
7721
|
const procedureTechnology = procedure.technology;
|
|
7713
7722
|
const procedureProduct = procedure.product;
|
|
7723
|
+
const productsMetadata = procedure.productsMetadata || [];
|
|
7714
7724
|
return {
|
|
7715
7725
|
id: procedure.id,
|
|
7716
7726
|
name: procedure.name,
|
|
@@ -7724,12 +7734,32 @@ var BookingAdmin = class {
|
|
|
7724
7734
|
procedureSubCategoryName: (procedureSubCategory == null ? void 0 : procedureSubCategory.name) || "",
|
|
7725
7735
|
procedureTechnologyId: (procedureTechnology == null ? void 0 : procedureTechnology.id) || "",
|
|
7726
7736
|
procedureTechnologyName: (procedureTechnology == null ? void 0 : procedureTechnology.name) || "",
|
|
7727
|
-
procedureProductBrandId: (
|
|
7728
|
-
procedureProductBrandName: (
|
|
7729
|
-
|
|
7730
|
-
|
|
7737
|
+
procedureProductBrandId: (procedureProduct == null ? void 0 : procedureProduct.brandId) || "",
|
|
7738
|
+
procedureProductBrandName: (procedureProduct == null ? void 0 : procedureProduct.brandName) || "",
|
|
7739
|
+
procedureProducts: productsMetadata.map((pp) => ({
|
|
7740
|
+
productId: pp.product.id,
|
|
7741
|
+
productName: pp.product.name,
|
|
7742
|
+
brandId: pp.product.brandId,
|
|
7743
|
+
brandName: pp.product.brandName
|
|
7744
|
+
}))
|
|
7731
7745
|
};
|
|
7732
7746
|
}
|
|
7747
|
+
_generateAppointmentProductsFromProcedure(procedure) {
|
|
7748
|
+
const productsMetadata = procedure.productsMetadata || [];
|
|
7749
|
+
return productsMetadata.map((pp) => {
|
|
7750
|
+
const product = pp.product;
|
|
7751
|
+
return {
|
|
7752
|
+
productId: product.id,
|
|
7753
|
+
productName: product.name,
|
|
7754
|
+
brandId: product.brandId,
|
|
7755
|
+
brandName: product.brandName,
|
|
7756
|
+
procedureId: procedure.id,
|
|
7757
|
+
price: pp.price,
|
|
7758
|
+
currency: pp.currency,
|
|
7759
|
+
unitOfMeasurement: pp.pricingMeasure
|
|
7760
|
+
};
|
|
7761
|
+
});
|
|
7762
|
+
}
|
|
7733
7763
|
};
|
|
7734
7764
|
|
|
7735
7765
|
// src/admin/free-consultation/free-consultation-utils.admin.ts
|