taxtank-core 0.29.18 → 0.29.20

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.
@@ -1368,6 +1368,7 @@ class ServiceProduct extends ServiceProduct$1 {
1368
1368
  return this.status === ServiceProductStatusEnum.ARCHIVED;
1369
1369
  }
1370
1370
  }
1371
+ ServiceProduct.quantity = 3;
1371
1372
  // const TestEnum = {
1372
1373
  // 4: 4,
1373
1374
  // 5: 7,
@@ -1402,204 +1403,325 @@ var ServiceSubscriptionStatusEnum;
1402
1403
  ServiceSubscriptionStatusEnum[ServiceSubscriptionStatusEnum["UNPAID"] = 6] = "UNPAID";
1403
1404
  })(ServiceSubscriptionStatusEnum || (ServiceSubscriptionStatusEnum = {}));
1404
1405
 
1405
- class ServiceSubscription extends ServiceSubscription$1 {
1406
- constructor() {
1407
- super(...arguments);
1408
- // Number of days after which the trial time will be expired
1409
- this.lastTrialDays = 4;
1406
+ class MessageCollection extends Collection {
1407
+ getFirstUnreadMessage(user) {
1408
+ return this.items.find((message) => {
1409
+ return !message.isRead() && message.isFromEmployee() !== user.isEmployee();
1410
+ });
1410
1411
  }
1411
- get isTrial() {
1412
- return !this.stripeId;
1412
+ /**
1413
+ * Get List of unread chats
1414
+ */
1415
+ getUnread() {
1416
+ return this.items.filter((message) => !message.readAt);
1413
1417
  }
1414
- get isPaid() {
1415
- return !!this.stripeId;
1418
+ getFromActiveChats() {
1419
+ return this.filter((message) => message.chat.isActive());
1416
1420
  }
1417
- get price() {
1418
- return this.items.reduce((sum, item) => sum + item.total, 0);
1421
+ /**
1422
+ * Get amount of chats that contains unread messages
1423
+ */
1424
+ getUnreadChatsAmount(isFromEmployee = false) {
1425
+ // filtered messages for client/employee
1426
+ const filteredMessages = this.filter((message) => isFromEmployee ? message.isFromEmployee() : !message.isFromEmployee());
1427
+ return uniqBy(filteredMessages.getFromActiveChats().getUnread(), 'chat.id').length;
1419
1428
  }
1420
1429
  /**
1421
- * get title of subscription
1430
+ * Check if chat has unread chats
1422
1431
  */
1423
- get title() {
1424
- return this.items.map((item) => item.price.product.title).join(' + ');
1425
- // return this.isTrial ? 'Trial period' : this.items.map((item) => item.price.product.title).join(' + ');
1432
+ hasUnread() {
1433
+ return !!this.getUnread().length;
1426
1434
  }
1435
+ }
1436
+
1437
+ var ChatStatusEnum;
1438
+ (function (ChatStatusEnum) {
1439
+ ChatStatusEnum[ChatStatusEnum["ACTIVE"] = 1] = "ACTIVE";
1440
+ ChatStatusEnum[ChatStatusEnum["INACTIVE"] = 2] = "INACTIVE";
1441
+ })(ChatStatusEnum || (ChatStatusEnum = {}));
1442
+
1443
+ class ChatCollection extends Collection {
1427
1444
  /**
1428
- * A subscription is considered active if the end date has not yet arrived and its status is "Active" or "Past due"
1445
+ * Sort chats by last messages (newest first) + empty chats in the end
1429
1446
  */
1430
- get isActive() {
1431
- const isExpired = new Date(this.endDate).getTime() < new Date().getTime();
1432
- return !isExpired && ([ServiceSubscriptionStatusEnum.ACTIVE, ServiceSubscriptionStatusEnum.PAST_DUE].includes(this.status));
1447
+ getSortedByNewest(messages) {
1448
+ const chatsById = new Dictionary(this.toArray());
1449
+ // get chats array sorted from newest to oldest
1450
+ const chats = uniqBy(new MessageCollection(messages)
1451
+ .filterBy('chat.id', this.getIds())
1452
+ .sortBy('createdAt', true)
1453
+ .toArray()
1454
+ .map((message) => chatsById.get(message.chat.id)), 'id');
1455
+ const emptyChats = differenceBy(this.toArray(), chats, 'id');
1456
+ return this.create([...chats, ...emptyChats]);
1433
1457
  }
1434
- get daysRemain() {
1435
- const daysRemains = Math.round((new Date(this.endDate).getTime() - new Date().getTime()) / (1000 * 3600 * 24));
1436
- return daysRemains > 0 ? daysRemains : 0;
1458
+ getActive() {
1459
+ return this.filterBy('status', ChatStatusEnum.ACTIVE);
1437
1460
  }
1461
+ }
1462
+
1463
+ /**
1464
+ * Collection of MessageDocument instances
1465
+ */
1466
+ class MessageDocumentCollection extends Collection {
1438
1467
  /**
1439
- * Check if trial expired
1468
+ * get list of documents which are not attached to any message
1440
1469
  */
1441
- isTrialExpired() {
1442
- return this.daysRemain && this.daysRemain <= 0;
1470
+ getUnattached() {
1471
+ return new MessageDocumentCollection(this.items.filter((doc) => !doc.message));
1443
1472
  }
1444
- isTrialExpiring() {
1445
- return this.daysRemain > 0 && this.daysRemain <= this.lastTrialDays;
1473
+ }
1474
+
1475
+ class LoanCollection extends Collection {
1476
+ /**
1477
+ * Get new collection of loans filtered by bank accounts ids
1478
+ * @param ids list of bank accounts ids for filter
1479
+ */
1480
+ getByBankAccountsIds(ids) {
1481
+ return new LoanCollection(this.items.filter((loan) => { var _a; return ids.includes((_a = loan.bankAccount) === null || _a === void 0 ? void 0 : _a.id); }));
1446
1482
  }
1447
- isRenewable() {
1448
- return !this.isTrial && this.isActive;
1483
+ /**
1484
+ * Get single loan by bank account id
1485
+ * @param id id of bank account
1486
+ */
1487
+ getByBankAccountId(id) {
1488
+ return this.items.find((loan) => { var _a; return ((_a = loan.bankAccount) === null || _a === void 0 ? void 0 : _a.id) === id; });
1449
1489
  }
1450
1490
  /**
1451
- * @TODO move to collection
1491
+ * Get list of current fin year payments grouped by loan id
1452
1492
  */
1453
- get workTankItem() {
1454
- return this.items.find((item) => item.price.product.isWorkTank());
1493
+ groupCurrentYearPaymentsByLoans() {
1494
+ const dictionary = new CollectionDictionary(new LoanPaymentCollection([]));
1495
+ this.items.forEach((loan) => dictionary.add(loan.id, new LoanPaymentCollection(loan.payments).getForCurrentYear()));
1496
+ return dictionary;
1455
1497
  }
1456
- get soleTankItem() {
1457
- return this.items.find((item) => item.price.product.isSoleTank());
1498
+ /**
1499
+ * Get list of vehicle loans
1500
+ */
1501
+ getVehicleLoans() {
1502
+ return this.filter((loan) => loan.isVehicle());
1458
1503
  }
1459
- get propertyTankItem() {
1460
- return this.items.find((item) => item.price.product.isProperties());
1504
+ }
1505
+
1506
+ class PropertySaleCollection extends Collection {
1507
+ get grossCGTAfterLoss() {
1508
+ return this.create(this.items.filter((propertySale) => propertySale.grossCGTAfterLoss > 0)).sumBy('grossCGTAfterLoss');
1461
1509
  }
1462
- hasPropertyTank() {
1463
- return !!this.items.find((subscriptionItem) => {
1464
- return subscriptionItem.price.product.role.includes(UserRolesEnum.PROPERTY_TANK);
1465
- });
1510
+ /**
1511
+ * Property sales are CGT applicable unless it has "Principle place of residence" exemption type
1512
+ */
1513
+ getCGTApplicable() {
1514
+ return this.create(this.items.filter((propertySale) => propertySale.isCGTApplicable()));
1466
1515
  }
1467
- hasWorkTank() {
1468
- return !!this.items.find((subscriptionItem) => {
1469
- return subscriptionItem.price.product.role.includes(UserRolesEnum.WORK_TANK);
1470
- });
1516
+ getByPropertyShareIds(ids) {
1517
+ return this.filterBy('share.id', ids);
1471
1518
  }
1519
+ }
1520
+
1521
+ var TaxExemptionMetadataEnum;
1522
+ (function (TaxExemptionMetadataEnum) {
1523
+ // principle place of residence
1524
+ TaxExemptionMetadataEnum[TaxExemptionMetadataEnum["PPR_DAYS"] = 1] = "PPR_DAYS";
1525
+ // market value once it was moved, decimal
1526
+ TaxExemptionMetadataEnum[TaxExemptionMetadataEnum["MARKET_VALUE"] = 2] = "MARKET_VALUE";
1527
+ TaxExemptionMetadataEnum[TaxExemptionMetadataEnum["CLAIM_PERCENT"] = 3] = "CLAIM_PERCENT";
1528
+ })(TaxExemptionMetadataEnum || (TaxExemptionMetadataEnum = {}));
1529
+
1530
+ class PropertySaleTaxExemptionMetadataCollection extends Collection {
1531
+ getPPRDays() {
1532
+ var _a, _b;
1533
+ return (_b = (_a = this.getByMetadataId(TaxExemptionMetadataEnum.PPR_DAYS)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : 0;
1534
+ }
1535
+ getMarketValue() {
1536
+ var _a, _b;
1537
+ return (_b = (_a = this.getByMetadataId(TaxExemptionMetadataEnum.MARKET_VALUE)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : 0;
1538
+ }
1539
+ getClaimPercent() {
1540
+ var _a, _b;
1541
+ return (_b = (_a = this.getByMetadataId(TaxExemptionMetadataEnum.CLAIM_PERCENT)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : 100;
1542
+ }
1543
+ getByMetadataId(id) {
1544
+ return this.items.find((metadata) => metadata.metadata.id === id);
1545
+ }
1546
+ }
1547
+
1548
+ class PropertyCollection extends Collection {
1472
1549
  /**
1473
- * bought before price updates, active for some time to let customer select a new plan
1474
- * impossible to update, only prolong or buy new
1550
+ * Get new property collection filtered by category id
1551
+ * @param id id of category for filter
1475
1552
  */
1476
- isArchived() {
1477
- // subscription with at least one archived product considered as archived
1478
- return !!this.items.filter((item) => item.price.product.isArchived()).length;
1553
+ getByCategoryId(id) {
1554
+ return new PropertyCollection(this.items.filter((property) => property.category.id === id));
1479
1555
  }
1480
1556
  /**
1481
- * Case when payment was failed, but user has a time to update payment method
1557
+ * Get new property collection filtered by active status
1482
1558
  */
1483
- isPastDue() {
1484
- return this.status === ServiceSubscriptionStatusEnum.PAST_DUE;
1559
+ getActiveProperties() {
1560
+ return new PropertyCollection(this.items.filter((property) => property.isActive));
1561
+ }
1562
+ getCreatedProperties() {
1563
+ return new PropertyCollection(this.items.filter((property) => property.isOwn()));
1485
1564
  }
1486
1565
  /**
1487
- * Check if current subscription has provided subscription item
1566
+ * Get new property collection filtered by shared
1488
1567
  */
1489
- hasItem(itemToCheck) {
1490
- return !!this.items.find((item) => item.price.id === itemToCheck.price.id);
1568
+ getSharedProperties() {
1569
+ return new PropertyCollection(this.items.filter((property) => !property.isOwn()));
1491
1570
  }
1492
- hasProduct(product) {
1493
- return !!this.items.find((item) => item.price.product.id === product.id);
1571
+ /**
1572
+ * Properties that are taxed and will be included in reports (Tax summary, My tax report, e.t.c.)
1573
+ */
1574
+ getTaxInclusive() {
1575
+ return this.create(this.items.filter((property) => property.category.isTaxInclusive));
1576
+ }
1577
+ getUnsold() {
1578
+ return this.create(this.items.filter((property) => !property.isSold()));
1494
1579
  }
1495
1580
  /**
1496
- * Recommended number of properties to buy,
1497
- * based on the property service product and the number of properties the user has
1581
+ * Get total purchase price for all properties in the collection
1498
1582
  */
1499
- getRecommendedPropertiesQty(propertyItem, propertiesQty) {
1500
- const min = propertyItem.price.product.minQty;
1501
- return Math.max(min, propertiesQty);
1583
+ get purchasePrice() {
1584
+ return this.sumBy('purchasePrice');
1502
1585
  }
1503
- }
1504
- __decorate([
1505
- Type(() => Date)
1506
- ], ServiceSubscription.prototype, "startDate", void 0);
1507
- __decorate([
1508
- Type(() => Date)
1509
- ], ServiceSubscription.prototype, "endDate", void 0);
1510
- __decorate([
1511
- Type(() => ServiceSubscriptionItem)
1512
- ], ServiceSubscription.prototype, "items", void 0);
1513
-
1514
- class SoleBusinessAllocation extends SoleBusinessAllocation$1 {
1515
- }
1516
- __decorate([
1517
- Type(() => BankAccount)
1518
- ], SoleBusinessAllocation.prototype, "bankAccount", void 0);
1519
- __decorate([
1520
- Type(() => SoleBusiness)
1521
- ], SoleBusinessAllocation.prototype, "business", void 0);
1522
- __decorate([
1523
- Transform(({ value }) => value || 100),
1524
- Expose()
1525
- ], SoleBusinessAllocation.prototype, "percent", void 0);
1526
-
1527
- class SoleBusinessLossOffsetRule extends SoleBusinessLossOffsetRule$1 {
1528
- }
1529
- __decorate([
1530
- Type(() => SoleBusinessLossOffsetRule)
1531
- ], SoleBusinessLossOffsetRule.prototype, "parent", void 0);
1532
-
1533
- /**
1534
- * If a sole trader business makes a tax loss in a current year, you can generally carry forward that loss and offset profit in future years.
1535
- * https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/4641357930/Rules+when+a+business+makes+a+loss+Tax+Summary#Offsetting-current-year-business-losses
1536
- */
1537
- class SoleBusinessLoss extends SoleBusinessLoss$1 {
1538
- constructor() {
1539
- super(...arguments);
1540
- this.openBalance = 0;
1541
- this.financialYear = new FinancialYear().year;
1586
+ get growthPercent() {
1587
+ return this.sumBy('growthPercent');
1542
1588
  }
1543
- get hasOffset() {
1544
- return !!this.offsetRule;
1589
+ get marketValue() {
1590
+ return this.sumBy('marketValue');
1591
+ }
1592
+ get firstForecastYear() {
1593
+ return this.items.reduce((min, property) => {
1594
+ const current = property.firstForecastYear;
1595
+ return min > current ? current : min;
1596
+ }, new FinancialYear().year);
1597
+ }
1598
+ get marketValueGrowth() {
1599
+ return (this.marketValue - this.purchasePrice) / this.purchasePrice;
1600
+ }
1601
+ /**
1602
+ * list of properties
1603
+ */
1604
+ getCGTApplicable() {
1605
+ return this.create(this.items.filter((property) => property.isCGTApplicable()));
1606
+ }
1607
+ getOwnerOccupiedProperties() {
1608
+ return new PropertyCollection(this.items.filter((property) => property.category.isOwnerOccupied()));
1609
+ }
1610
+ get earliestContractDate() {
1611
+ return this.items.reduce((min, property) => {
1612
+ return min < property.contractDate ? min : property.contractDate;
1613
+ }, new FinancialYear(new Date()).startDate);
1614
+ }
1615
+ /**
1616
+ * Get list of unique property categories from collection
1617
+ */
1618
+ getCategories() {
1619
+ return uniqBy(this.items.map((property) => property.category), 'id');
1620
+ }
1621
+ /**
1622
+ * Get property with the highest growth percent
1623
+ */
1624
+ getBestPerformanceGrowthProperty() {
1625
+ return this.items.reduce((max, current) => {
1626
+ return max.growthPercent < current.growthPercent ? current : max;
1627
+ }, this.first);
1628
+ }
1629
+ /**
1630
+ * Get property with the lowest tax position
1631
+ */
1632
+ getBestPerformanceTaxProperty(transactions, depreciations) {
1633
+ const transactionsByProperty = transactions.groupBy('property.id');
1634
+ const depreciationsByProperty = depreciations.groupBy('property.id');
1635
+ return this.items.reduce((min, current) => {
1636
+ const minTaxPosition = min.getTaxPosition(transactionsByProperty.get(min.id), depreciationsByProperty.get(min.id));
1637
+ const currentTaxPosition = current.getTaxPosition(transactionsByProperty.get(current.id), depreciationsByProperty.get(current.id));
1638
+ return minTaxPosition > currentTaxPosition ? current : min;
1639
+ }, this.first);
1640
+ }
1641
+ /**
1642
+ * Show best performance properties first
1643
+ * https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/217677997/Property+Tank+Dashboard
1644
+ */
1645
+ sortByBestPerformance(transactions, depreciations) {
1646
+ const activeProperties = this.getActiveProperties();
1647
+ // nothing to sort when no active properties
1648
+ if (!activeProperties.length) {
1649
+ return this;
1650
+ }
1651
+ const bestProperties = uniqBy(this.create([
1652
+ activeProperties.getBestPerformanceGrowthProperty(),
1653
+ activeProperties.getBestPerformanceTaxProperty(transactions, depreciations)
1654
+ ]).toArray(), 'id');
1655
+ const newItems = this.remove(bestProperties).toArray();
1656
+ newItems.unshift(...bestProperties);
1657
+ return this.create(newItems);
1545
1658
  }
1546
1659
  }
1547
- __decorate([
1548
- Type(() => SoleBusiness)
1549
- ], SoleBusinessLoss.prototype, "business", void 0);
1550
- __decorate([
1551
- Type(() => SoleBusinessLossOffsetRule)
1552
- ], SoleBusinessLoss.prototype, "offsetRule", void 0);
1553
-
1554
- var MyAccountHistoryInitiatedByEnum;
1555
- (function (MyAccountHistoryInitiatedByEnum) {
1556
- MyAccountHistoryInitiatedByEnum[MyAccountHistoryInitiatedByEnum["OWNER"] = 0] = "OWNER";
1557
- MyAccountHistoryInitiatedByEnum[MyAccountHistoryInitiatedByEnum["ACCOUNTANT"] = 1] = "ACCOUNTANT";
1558
- })(MyAccountHistoryInitiatedByEnum || (MyAccountHistoryInitiatedByEnum = {}));
1559
-
1560
- var MyAccountHistoryStatusEnum;
1561
- (function (MyAccountHistoryStatusEnum) {
1562
- MyAccountHistoryStatusEnum[MyAccountHistoryStatusEnum["SUCCESS"] = 0] = "SUCCESS";
1563
- MyAccountHistoryStatusEnum[MyAccountHistoryStatusEnum["ERROR"] = 1] = "ERROR";
1564
- })(MyAccountHistoryStatusEnum || (MyAccountHistoryStatusEnum = {}));
1565
1660
 
1566
- var MyAccountHistoryTypeEnum;
1567
- (function (MyAccountHistoryTypeEnum) {
1568
- MyAccountHistoryTypeEnum[MyAccountHistoryTypeEnum["REVIEW"] = 0] = "REVIEW";
1569
- MyAccountHistoryTypeEnum[MyAccountHistoryTypeEnum["UPGRADE_PLAN"] = 1] = "UPGRADE_PLAN";
1570
- MyAccountHistoryTypeEnum[MyAccountHistoryTypeEnum["UPLOAD_DOCUMENT"] = 2] = "UPLOAD_DOCUMENT";
1571
- })(MyAccountHistoryTypeEnum || (MyAccountHistoryTypeEnum = {}));
1572
-
1573
- class MyAccountHistory {
1661
+ class PropertyCategoryMovementCollection extends Collection {
1662
+ /**
1663
+ * @TODO TT-2355 Alex refactor propertyForecast, use separated api (then I can remove property from param)
1664
+ */
1665
+ getByForecast(property, forecast) {
1666
+ const financialYear = new FinancialYear(forecast.financialYear);
1667
+ return this.filterBy('property.id', property.id).filter((movement) => {
1668
+ return movement.fromDate <= financialYear.endDate && !movement.toDate || movement.toDate >= financialYear.startDate;
1669
+ });
1670
+ }
1671
+ hasCategory(categoryId) {
1672
+ return !!this.findBy('propertyCategory.id', categoryId);
1673
+ }
1574
1674
  }
1575
1675
 
1576
- class Occupation extends Occupation$1 {
1676
+ class PropertyShareCollection extends Collection {
1677
+ /**
1678
+ * Get list of incoming property shares
1679
+ * (initiated not by current user)
1680
+ * @TODO Alex: rename
1681
+ */
1682
+ getIncoming() {
1683
+ return this.filter((propertyShare) => {
1684
+ var _a;
1685
+ return ((_a = propertyShare.user) === null || _a === void 0 ? void 0 : _a.isLoggedIn()) && propertyShare.isPending() && propertyShare.property.user.id !== +localStorage.getItem('userId');
1686
+ });
1687
+ }
1688
+ /**
1689
+ * Get list of outcoming property shares
1690
+ * (initiated by current user)
1691
+ * @TODO Alex: rename
1692
+ */
1693
+ getOutcoming() {
1694
+ return this.filter((propertyShare) => { var _a; return !((_a = propertyShare.user) === null || _a === void 0 ? void 0 : _a.isLoggedIn()); });
1695
+ }
1577
1696
  }
1578
1697
 
1579
1698
  /**
1580
- * role hierarchy
1699
+ * Enum with symbols based on depreciation LVP asset type
1581
1700
  */
1582
- const USER_ROLES = {
1583
- ROLE_FIRM_OWNER: [UserRolesEnum.FIRM_OWNER, UserRolesEnum.FIRM_MANAGER, UserRolesEnum.ACCOUNTANT, UserRolesEnum.ADVISOR],
1584
- ROLE_FIRM_MANAGER: [UserRolesEnum.FIRM_MANAGER, UserRolesEnum.ACCOUNTANT, UserRolesEnum.ADVISOR],
1585
- ROLE_EMPLOYEE: [UserRolesEnum.ACCOUNTANT, UserRolesEnum.ADVISOR],
1586
- ROLE_ACCOUNTANT: [UserRolesEnum.ACCOUNTANT],
1587
- ROLE_ADVISOR: [UserRolesEnum.ADVISOR],
1588
- ROLE_CLIENT: [UserRolesEnum.CLIENT],
1589
- ROLE_USER_SUBSCRIPTION: [UserRolesEnum.SUBSCRIPTION],
1590
- ROLE_USER_WORK: [UserRolesEnum.WORK_TANK],
1591
- ROLE_USER_PROPERTY: [UserRolesEnum.PROPERTY_TANK],
1592
- ROLE_USER_SOLE: [UserRolesEnum.SOLE_TANK],
1593
- };
1701
+ var DepreciationLvpAssetTypeEnum;
1702
+ (function (DepreciationLvpAssetTypeEnum) {
1703
+ DepreciationLvpAssetTypeEnum["PRIOR_YEARS"] = "A";
1704
+ DepreciationLvpAssetTypeEnum["FIRST_YEAR"] = "L";
1705
+ DepreciationLvpAssetTypeEnum["WRITTEN_OFF"] = "W";
1706
+ })(DepreciationLvpAssetTypeEnum || (DepreciationLvpAssetTypeEnum = {}));
1594
1707
 
1595
- /**
1596
- * Class with basic information about registering user
1597
- */
1598
- class UserToRegister {
1599
- }
1708
+ var DepreciationTypeEnum;
1709
+ (function (DepreciationTypeEnum) {
1710
+ DepreciationTypeEnum[DepreciationTypeEnum["PLANT_EQUIPMENT"] = 1] = "PLANT_EQUIPMENT";
1711
+ DepreciationTypeEnum[DepreciationTypeEnum["CAPITAL_WORKS"] = 2] = "CAPITAL_WORKS";
1712
+ DepreciationTypeEnum[DepreciationTypeEnum["BULK_DEPRECIATION"] = 3] = "BULK_DEPRECIATION";
1713
+ DepreciationTypeEnum[DepreciationTypeEnum["BORROWING_EXPENSES"] = 4] = "BORROWING_EXPENSES";
1714
+ })(DepreciationTypeEnum || (DepreciationTypeEnum = {}));
1600
1715
 
1601
- class ChartAccountsHeading extends ChartAccountsHeading$1 {
1602
- }
1716
+ var DepreciationCalculationEnum;
1717
+ (function (DepreciationCalculationEnum) {
1718
+ DepreciationCalculationEnum[DepreciationCalculationEnum["PRIME_COST"] = 1] = "PRIME_COST";
1719
+ DepreciationCalculationEnum[DepreciationCalculationEnum["DIMINISHING"] = 2] = "DIMINISHING";
1720
+ DepreciationCalculationEnum[DepreciationCalculationEnum["CAPITAL"] = 3] = "CAPITAL";
1721
+ DepreciationCalculationEnum[DepreciationCalculationEnum["LVP"] = 4] = "LVP";
1722
+ DepreciationCalculationEnum[DepreciationCalculationEnum["AMORTISATION"] = 5] = "AMORTISATION";
1723
+ DepreciationCalculationEnum[DepreciationCalculationEnum["SBP"] = 6] = "SBP";
1724
+ })(DepreciationCalculationEnum || (DepreciationCalculationEnum = {}));
1603
1725
 
1604
1726
  var DocumentTypeEnum;
1605
1727
  (function (DocumentTypeEnum) {
@@ -1883,15 +2005,40 @@ var ChartAccountsKeepSign;
1883
2005
 
1884
2006
  // @TODO Artem TT-2308 move everything
1885
2007
 
1886
- class ChartAccountsMetadata extends ChartAccountsMetadata$1 {
1887
- /**
1888
- * Check if metadata id is related to SHARE_PERCENTAGE value
1889
- */
1890
- isSharePercentage() {
1891
- return this.id === ChartAccountsMetadataListEnum.SHARE_PERCENTAGE;
2008
+ class DepreciationCapitalProject extends DepreciationCapitalProject$1 {
2009
+ }
2010
+ __decorate([
2011
+ Type(() => Date)
2012
+ ], DepreciationCapitalProject.prototype, "effectiveDate", void 0);
2013
+
2014
+ class DepreciationForecast extends DepreciationForecast$1 {
2015
+ get dailyClaimAmount() {
2016
+ return this.claimAmount / this.daysApplied;
1892
2017
  }
1893
- isHours() {
1894
- return this.id === ChartAccountsMetadataListEnum.HOURS;
2018
+ get daysApplied() {
2019
+ return moment$1(this.toDate).diff(moment$1(this.fromDate), 'days');
2020
+ }
2021
+ getDaysByMonth(month) {
2022
+ // @TODO find a better place
2023
+ const year = this.financialYear - (month > 5 ? 1 : 0);
2024
+ // forecast date intersect by month
2025
+ const range = new DateRange(this.fromDate, this.toDate).intersect(new DateRange(new Date(year, month, 1), new Date(year, month + 1, 0)));
2026
+ return range ? range.duration('days') + 1 : 0;
2027
+ }
2028
+ get claimOpenBalance() {
2029
+ return this.openBalance * this.claimRate;
2030
+ }
2031
+ get claimCloseBalance() {
2032
+ return this.closeBalance * this.claimRate;
2033
+ }
2034
+ get claimAmount() {
2035
+ return this.amount * this.claimRate;
2036
+ }
2037
+ get claimRate() {
2038
+ return this.claimPercent / 100;
2039
+ }
2040
+ getClaimAmountByMonth(month) {
2041
+ return this.getDaysByMonth(month) * this.dailyClaimAmount;
1895
2042
  }
1896
2043
  }
1897
2044
 
@@ -1996,6 +2143,68 @@ const CHART_ACCOUNTS_CATEGORIES = {
1996
2143
  ]
1997
2144
  };
1998
2145
 
2146
+ /**
2147
+ * @TODO Alex/Vik: think and create some new collection type
2148
+ * @TODO Alex: research all constants and make the same structure
2149
+ */
2150
+ class ChartAccountsCategoryECollection {
2151
+ constructor(items) {
2152
+ this.items = items || [
2153
+ ChartAccountsCategoryEnum.PROPERTY_INCOME,
2154
+ ChartAccountsCategoryEnum.PROPERTY_EXPENSE,
2155
+ ChartAccountsCategoryEnum.PROPERTY_DEPRECIATION,
2156
+ ChartAccountsCategoryEnum.PROPERTY_CAPITAL_WORKS,
2157
+ ChartAccountsCategoryEnum.WORK_DEPRECIATION,
2158
+ ChartAccountsCategoryEnum.WORK_INCOME,
2159
+ ChartAccountsCategoryEnum.WORK_EXPENSE,
2160
+ ChartAccountsCategoryEnum.OTHER_INCOME,
2161
+ ChartAccountsCategoryEnum.OTHER_EXPENSE,
2162
+ ChartAccountsCategoryEnum.PERSONAL_INCOME,
2163
+ ChartAccountsCategoryEnum.PERSONAL_EXPENSE,
2164
+ ChartAccountsCategoryEnum.SOLE_INCOME,
2165
+ ChartAccountsCategoryEnum.SOLE_EXPENSE,
2166
+ ChartAccountsCategoryEnum.SOLE_DEPRECIATION
2167
+ ];
2168
+ }
2169
+ getByType(types) {
2170
+ if (!Array.isArray(types)) {
2171
+ types = [types];
2172
+ }
2173
+ const items = [];
2174
+ types.forEach((type) => {
2175
+ const filtered = this.items.filter((item) => ChartAccountsCategoryEnum[item].includes(type.toUpperCase()));
2176
+ items.push(...filtered);
2177
+ });
2178
+ return new ChartAccountsCategoryECollection(items);
2179
+ }
2180
+ getByTankType(tankTypes) {
2181
+ if (!Array.isArray(tankTypes)) {
2182
+ tankTypes = [tankTypes];
2183
+ }
2184
+ const items = [];
2185
+ tankTypes.forEach((tankType) => {
2186
+ const filtered = this.items.filter((item) => ChartAccountsCategoryEnum[item].includes(tankType.toUpperCase()));
2187
+ items.push(...filtered);
2188
+ });
2189
+ return new ChartAccountsCategoryECollection(items);
2190
+ }
2191
+ }
2192
+
2193
+ class ChartAccountsHeading extends ChartAccountsHeading$1 {
2194
+ }
2195
+
2196
+ class ChartAccountsMetadata extends ChartAccountsMetadata$1 {
2197
+ /**
2198
+ * Check if metadata id is related to SHARE_PERCENTAGE value
2199
+ */
2200
+ isSharePercentage() {
2201
+ return this.id === ChartAccountsMetadataListEnum.SHARE_PERCENTAGE;
2202
+ }
2203
+ isHours() {
2204
+ return this.id === ChartAccountsMetadataListEnum.HOURS;
2205
+ }
2206
+ }
2207
+
1999
2208
  var ChartAccountsTaxLabelsEnum;
2000
2209
  (function (ChartAccountsTaxLabelsEnum) {
2001
2210
  ChartAccountsTaxLabelsEnum["TAX_WITHHELD"] = "Tax withheld";
@@ -2217,6 +2426,30 @@ __decorate([
2217
2426
  Type(() => ChartAccountsMetadata)
2218
2427
  ], ChartAccounts.prototype, "metadata", void 0);
2219
2428
 
2429
+ class ChartAccountsDepreciation extends ChartAccountsDepreciation$1 {
2430
+ }
2431
+ __decorate([
2432
+ Type(() => ChartAccounts)
2433
+ ], ChartAccountsDepreciation.prototype, "chartAccounts", void 0);
2434
+ __decorate([
2435
+ Transform(({ value }) => +value)
2436
+ ], ChartAccountsDepreciation.prototype, "limit", void 0);
2437
+ __decorate([
2438
+ Transform(({ value }) => +value)
2439
+ ], ChartAccountsDepreciation.prototype, "effectiveLife", void 0);
2440
+
2441
+ class ChartAccountsValue extends ChartAccountsValue$1 {
2442
+ }
2443
+
2444
+ /**
2445
+ * Enum with income amount types (Net or Gross)
2446
+ */
2447
+ var IncomeAmountTypeEnum;
2448
+ (function (IncomeAmountTypeEnum) {
2449
+ IncomeAmountTypeEnum[IncomeAmountTypeEnum["NET"] = 0] = "NET";
2450
+ IncomeAmountTypeEnum[IncomeAmountTypeEnum["GROSS"] = 1] = "GROSS";
2451
+ })(IncomeAmountTypeEnum || (IncomeAmountTypeEnum = {}));
2452
+
2220
2453
  var TransactionTypeEnum;
2221
2454
  (function (TransactionTypeEnum) {
2222
2455
  TransactionTypeEnum[TransactionTypeEnum["DEBIT"] = 1] = "DEBIT";
@@ -2237,24 +2470,6 @@ var TransactionSourceEnum;
2237
2470
  TransactionSourceEnum[TransactionSourceEnum["BANK_TRANSACTION"] = 2] = "BANK_TRANSACTION";
2238
2471
  })(TransactionSourceEnum || (TransactionSourceEnum = {}));
2239
2472
 
2240
- var DepreciationTypeEnum;
2241
- (function (DepreciationTypeEnum) {
2242
- DepreciationTypeEnum[DepreciationTypeEnum["PLANT_EQUIPMENT"] = 1] = "PLANT_EQUIPMENT";
2243
- DepreciationTypeEnum[DepreciationTypeEnum["CAPITAL_WORKS"] = 2] = "CAPITAL_WORKS";
2244
- DepreciationTypeEnum[DepreciationTypeEnum["BULK_DEPRECIATION"] = 3] = "BULK_DEPRECIATION";
2245
- DepreciationTypeEnum[DepreciationTypeEnum["BORROWING_EXPENSES"] = 4] = "BORROWING_EXPENSES";
2246
- })(DepreciationTypeEnum || (DepreciationTypeEnum = {}));
2247
-
2248
- var DepreciationCalculationEnum;
2249
- (function (DepreciationCalculationEnum) {
2250
- DepreciationCalculationEnum[DepreciationCalculationEnum["PRIME_COST"] = 1] = "PRIME_COST";
2251
- DepreciationCalculationEnum[DepreciationCalculationEnum["DIMINISHING"] = 2] = "DIMINISHING";
2252
- DepreciationCalculationEnum[DepreciationCalculationEnum["CAPITAL"] = 3] = "CAPITAL";
2253
- DepreciationCalculationEnum[DepreciationCalculationEnum["LVP"] = 4] = "LVP";
2254
- DepreciationCalculationEnum[DepreciationCalculationEnum["AMORTISATION"] = 5] = "AMORTISATION";
2255
- DepreciationCalculationEnum[DepreciationCalculationEnum["SBP"] = 6] = "SBP";
2256
- })(DepreciationCalculationEnum || (DepreciationCalculationEnum = {}));
2257
-
2258
2473
  /**
2259
2474
  * Enum with asset types
2260
2475
  */
@@ -2290,68 +2505,6 @@ class TransactionReceipt extends TransactionReceipt$1 {
2290
2505
  }
2291
2506
  }
2292
2507
 
2293
- /**
2294
- * @TODO Alex/Vik: think and create some new collection type
2295
- * @TODO Alex: research all constants and make the same structure
2296
- */
2297
- class ChartAccountsCategoryECollection {
2298
- constructor(items) {
2299
- this.items = items || [
2300
- ChartAccountsCategoryEnum.PROPERTY_INCOME,
2301
- ChartAccountsCategoryEnum.PROPERTY_EXPENSE,
2302
- ChartAccountsCategoryEnum.PROPERTY_DEPRECIATION,
2303
- ChartAccountsCategoryEnum.PROPERTY_CAPITAL_WORKS,
2304
- ChartAccountsCategoryEnum.WORK_DEPRECIATION,
2305
- ChartAccountsCategoryEnum.WORK_INCOME,
2306
- ChartAccountsCategoryEnum.WORK_EXPENSE,
2307
- ChartAccountsCategoryEnum.OTHER_INCOME,
2308
- ChartAccountsCategoryEnum.OTHER_EXPENSE,
2309
- ChartAccountsCategoryEnum.PERSONAL_INCOME,
2310
- ChartAccountsCategoryEnum.PERSONAL_EXPENSE,
2311
- ChartAccountsCategoryEnum.SOLE_INCOME,
2312
- ChartAccountsCategoryEnum.SOLE_EXPENSE,
2313
- ChartAccountsCategoryEnum.SOLE_DEPRECIATION
2314
- ];
2315
- }
2316
- getByType(types) {
2317
- if (!Array.isArray(types)) {
2318
- types = [types];
2319
- }
2320
- const items = [];
2321
- types.forEach((type) => {
2322
- const filtered = this.items.filter((item) => ChartAccountsCategoryEnum[item].includes(type.toUpperCase()));
2323
- items.push(...filtered);
2324
- });
2325
- return new ChartAccountsCategoryECollection(items);
2326
- }
2327
- getByTankType(tankTypes) {
2328
- if (!Array.isArray(tankTypes)) {
2329
- tankTypes = [tankTypes];
2330
- }
2331
- const items = [];
2332
- tankTypes.forEach((tankType) => {
2333
- const filtered = this.items.filter((item) => ChartAccountsCategoryEnum[item].includes(tankType.toUpperCase()));
2334
- items.push(...filtered);
2335
- });
2336
- return new ChartAccountsCategoryECollection(items);
2337
- }
2338
- }
2339
-
2340
- class ChartAccountsDepreciation extends ChartAccountsDepreciation$1 {
2341
- }
2342
- __decorate([
2343
- Type(() => ChartAccounts)
2344
- ], ChartAccountsDepreciation.prototype, "chartAccounts", void 0);
2345
- __decorate([
2346
- Transform(({ value }) => +value)
2347
- ], ChartAccountsDepreciation.prototype, "limit", void 0);
2348
- __decorate([
2349
- Transform(({ value }) => +value)
2350
- ], ChartAccountsDepreciation.prototype, "effectiveLife", void 0);
2351
-
2352
- class ChartAccountsValue extends ChartAccountsValue$1 {
2353
- }
2354
-
2355
2508
  var IncomeSourceTypeEnum;
2356
2509
  (function (IncomeSourceTypeEnum) {
2357
2510
  IncomeSourceTypeEnum[IncomeSourceTypeEnum["WORK"] = 1] = "WORK";
@@ -2545,414 +2698,281 @@ class BankTransaction extends BankTransaction$1 {
2545
2698
  /**
2546
2699
  * check if bank transaction is debit
2547
2700
  */
2548
- isDebit() {
2549
- return this.type === BankTransactionTypeEnum.DEBIT;
2550
- }
2551
- /**
2552
- * check if bank transaction is credit
2553
- */
2554
- isCredit() {
2555
- return this.type === BankTransactionTypeEnum.CREDIT;
2556
- }
2557
- /**
2558
- * Create Transaction instance based on Bank Transaction
2559
- */
2560
- toTransaction() {
2561
- return plainToClass(Transaction, {
2562
- amount: +this.amount.toFixed(2),
2563
- description: this.description,
2564
- date: this.date,
2565
- source: TransactionSourceEnum.BANK_TRANSACTION,
2566
- operation: this.operation,
2567
- type: this.type,
2568
- });
2569
- }
2570
- /**
2571
- * Check if bank transaction is completely allocated
2572
- */
2573
- isAllocated(allocations) {
2574
- return this.amount === this.getAllocatedAmount(allocations);
2575
- }
2576
- /**
2577
- * Get bank transaction allocated amount
2578
- */
2579
- getAllocatedAmount(allocations) {
2580
- return allocations.getByBankTransactionsIds([this.id]).amount;
2581
- }
2582
- /**
2583
- * Get bank transaction unallocated amount
2584
- */
2585
- getUnallocatedAmount(allocations) {
2586
- return this.amount - this.getAllocatedAmount(allocations);
2587
- }
2588
- }
2589
- __decorate([
2590
- Type(() => Date)
2591
- ], BankTransaction.prototype, "date", void 0);
2592
-
2593
- class TransactionAllocation extends TransactionAllocation$1 {
2594
- /**
2595
- * Create a new instance of transaction allocation
2596
- * transaction could be empty since we can POST allocation inside a new transaction
2597
- */
2598
- static create(amount, bankTransaction, transaction) {
2599
- return plainToClass(TransactionAllocation, { amount, transaction, bankTransaction });
2600
- }
2601
- }
2602
- __decorate([
2603
- Type(() => BankTransaction)
2604
- ], TransactionAllocation.prototype, "bankTransaction", void 0);
2605
- __decorate([
2606
- Type(() => Transaction)
2607
- ], TransactionAllocation.prototype, "transaction", void 0);
2608
-
2609
- class MessageCollection extends Collection {
2610
- getFirstUnreadMessage(user) {
2611
- return this.items.find((message) => {
2612
- return !message.isRead() && message.isFromEmployee() !== user.isEmployee();
2613
- });
2614
- }
2615
- /**
2616
- * Get List of unread chats
2617
- */
2618
- getUnread() {
2619
- return this.items.filter((message) => !message.readAt);
2620
- }
2621
- getFromActiveChats() {
2622
- return this.filter((message) => message.chat.isActive());
2623
- }
2624
- /**
2625
- * Get amount of chats that contains unread messages
2626
- */
2627
- getUnreadChatsAmount(isFromEmployee = false) {
2628
- // filtered messages for client/employee
2629
- const filteredMessages = this.filter((message) => isFromEmployee ? message.isFromEmployee() : !message.isFromEmployee());
2630
- return uniqBy(filteredMessages.getFromActiveChats().getUnread(), 'chat.id').length;
2631
- }
2632
- /**
2633
- * Check if chat has unread chats
2634
- */
2635
- hasUnread() {
2636
- return !!this.getUnread().length;
2637
- }
2638
- }
2639
-
2640
- var ChatStatusEnum;
2641
- (function (ChatStatusEnum) {
2642
- ChatStatusEnum[ChatStatusEnum["ACTIVE"] = 1] = "ACTIVE";
2643
- ChatStatusEnum[ChatStatusEnum["INACTIVE"] = 2] = "INACTIVE";
2644
- })(ChatStatusEnum || (ChatStatusEnum = {}));
2645
-
2646
- class ChatCollection extends Collection {
2647
- /**
2648
- * Sort chats by last messages (newest first) + empty chats in the end
2649
- */
2650
- getSortedByNewest(messages) {
2651
- const chatsById = new Dictionary(this.toArray());
2652
- // get chats array sorted from newest to oldest
2653
- const chats = uniqBy(new MessageCollection(messages)
2654
- .filterBy('chat.id', this.getIds())
2655
- .sortBy('createdAt', true)
2656
- .toArray()
2657
- .map((message) => chatsById.get(message.chat.id)), 'id');
2658
- const emptyChats = differenceBy(this.toArray(), chats, 'id');
2659
- return this.create([...chats, ...emptyChats]);
2660
- }
2661
- getActive() {
2662
- return this.filterBy('status', ChatStatusEnum.ACTIVE);
2701
+ isDebit() {
2702
+ return this.type === BankTransactionTypeEnum.DEBIT;
2663
2703
  }
2664
- }
2665
-
2666
- /**
2667
- * Collection of MessageDocument instances
2668
- */
2669
- class MessageDocumentCollection extends Collection {
2670
2704
  /**
2671
- * get list of documents which are not attached to any message
2705
+ * check if bank transaction is credit
2672
2706
  */
2673
- getUnattached() {
2674
- return new MessageDocumentCollection(this.items.filter((doc) => !doc.message));
2707
+ isCredit() {
2708
+ return this.type === BankTransactionTypeEnum.CREDIT;
2675
2709
  }
2676
- }
2677
-
2678
- class LoanCollection extends Collection {
2679
2710
  /**
2680
- * Get new collection of loans filtered by bank accounts ids
2681
- * @param ids list of bank accounts ids for filter
2711
+ * Create Transaction instance based on Bank Transaction
2682
2712
  */
2683
- getByBankAccountsIds(ids) {
2684
- return new LoanCollection(this.items.filter((loan) => { var _a; return ids.includes((_a = loan.bankAccount) === null || _a === void 0 ? void 0 : _a.id); }));
2713
+ toTransaction() {
2714
+ return plainToClass(Transaction, {
2715
+ amount: +this.amount.toFixed(2),
2716
+ description: this.description,
2717
+ date: this.date,
2718
+ source: TransactionSourceEnum.BANK_TRANSACTION,
2719
+ operation: this.operation,
2720
+ type: this.type,
2721
+ });
2685
2722
  }
2686
2723
  /**
2687
- * Get single loan by bank account id
2688
- * @param id id of bank account
2724
+ * Check if bank transaction is completely allocated
2689
2725
  */
2690
- getByBankAccountId(id) {
2691
- return this.items.find((loan) => { var _a; return ((_a = loan.bankAccount) === null || _a === void 0 ? void 0 : _a.id) === id; });
2726
+ isAllocated(allocations) {
2727
+ return this.amount === this.getAllocatedAmount(allocations);
2692
2728
  }
2693
2729
  /**
2694
- * Get list of current fin year payments grouped by loan id
2730
+ * Get bank transaction allocated amount
2695
2731
  */
2696
- groupCurrentYearPaymentsByLoans() {
2697
- const dictionary = new CollectionDictionary(new LoanPaymentCollection([]));
2698
- this.items.forEach((loan) => dictionary.add(loan.id, new LoanPaymentCollection(loan.payments).getForCurrentYear()));
2699
- return dictionary;
2732
+ getAllocatedAmount(allocations) {
2733
+ return allocations.getByBankTransactionsIds([this.id]).amount;
2700
2734
  }
2701
2735
  /**
2702
- * Get list of vehicle loans
2736
+ * Get bank transaction unallocated amount
2703
2737
  */
2704
- getVehicleLoans() {
2705
- return this.filter((loan) => loan.isVehicle());
2738
+ getUnallocatedAmount(allocations) {
2739
+ return this.amount - this.getAllocatedAmount(allocations);
2706
2740
  }
2707
2741
  }
2742
+ __decorate([
2743
+ Type(() => Date)
2744
+ ], BankTransaction.prototype, "date", void 0);
2708
2745
 
2709
- class PropertySaleCollection extends Collection {
2710
- get grossCGTAfterLoss() {
2711
- return this.create(this.items.filter((propertySale) => propertySale.grossCGTAfterLoss > 0)).sumBy('grossCGTAfterLoss');
2712
- }
2746
+ class TransactionAllocation extends TransactionAllocation$1 {
2713
2747
  /**
2714
- * Property sales are CGT applicable unless it has "Principle place of residence" exemption type
2748
+ * Create a new instance of transaction allocation
2749
+ * transaction could be empty since we can POST allocation inside a new transaction
2715
2750
  */
2716
- getCGTApplicable() {
2717
- return this.create(this.items.filter((propertySale) => propertySale.isCGTApplicable()));
2718
- }
2719
- getByPropertyShareIds(ids) {
2720
- return this.filterBy('share.id', ids);
2751
+ static create(amount, bankTransaction, transaction) {
2752
+ return plainToClass(TransactionAllocation, { amount, transaction, bankTransaction });
2721
2753
  }
2722
2754
  }
2755
+ __decorate([
2756
+ Type(() => BankTransaction)
2757
+ ], TransactionAllocation.prototype, "bankTransaction", void 0);
2758
+ __decorate([
2759
+ Type(() => Transaction)
2760
+ ], TransactionAllocation.prototype, "transaction", void 0);
2723
2761
 
2724
- var TaxExemptionMetadataEnum;
2725
- (function (TaxExemptionMetadataEnum) {
2726
- // principle place of residence
2727
- TaxExemptionMetadataEnum[TaxExemptionMetadataEnum["PPR_DAYS"] = 1] = "PPR_DAYS";
2728
- // market value once it was moved, decimal
2729
- TaxExemptionMetadataEnum[TaxExemptionMetadataEnum["MARKET_VALUE"] = 2] = "MARKET_VALUE";
2730
- TaxExemptionMetadataEnum[TaxExemptionMetadataEnum["CLAIM_PERCENT"] = 3] = "CLAIM_PERCENT";
2731
- })(TaxExemptionMetadataEnum || (TaxExemptionMetadataEnum = {}));
2732
-
2733
- class PropertySaleTaxExemptionMetadataCollection extends Collection {
2734
- getPPRDays() {
2735
- var _a, _b;
2736
- return (_b = (_a = this.getByMetadataId(TaxExemptionMetadataEnum.PPR_DAYS)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : 0;
2737
- }
2738
- getMarketValue() {
2739
- var _a, _b;
2740
- return (_b = (_a = this.getByMetadataId(TaxExemptionMetadataEnum.MARKET_VALUE)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : 0;
2762
+ // @TODO Alex: refactor: move here allocations methods, netAmount = amount, grossAmount calculation, remove unused methods, etc.
2763
+ class Transaction extends Transaction$1 {
2764
+ constructor() {
2765
+ super(...arguments);
2766
+ // list of child transactions (fees)
2767
+ this.transactions = [];
2768
+ this.metadata = [];
2769
+ this.allocations = [];
2770
+ this.tax = 0;
2771
+ this.operation = TransactionOperationEnum.FIND_AND_MATCH;
2772
+ this.claimPercent = 100;
2773
+ this.amount = 0;
2741
2774
  }
2742
- getClaimPercent() {
2743
- var _a, _b;
2744
- return (_b = (_a = this.getByMetadataId(TaxExemptionMetadataEnum.CLAIM_PERCENT)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : 100;
2775
+ isDebit() {
2776
+ return this.type === TransactionTypeEnum.DEBIT;
2745
2777
  }
2746
- getByMetadataId(id) {
2747
- return this.items.find((metadata) => metadata.metadata.id === id);
2778
+ isCredit() {
2779
+ return this.type === TransactionTypeEnum.CREDIT;
2748
2780
  }
2749
- }
2750
-
2751
- class PropertyCollection extends Collection {
2752
2781
  /**
2753
- * Get new property collection filtered by category id
2754
- * @param id id of category for filter
2782
+ * @TODO move to base collection
2755
2783
  */
2756
- getByCategoryId(id) {
2757
- return new PropertyCollection(this.items.filter((property) => property.category.id === id));
2784
+ isIncome() {
2785
+ // @TODO not used
2786
+ if (!this.chartAccounts) {
2787
+ return this.isCredit();
2788
+ }
2789
+ return CHART_ACCOUNTS_CATEGORIES.income.includes(this.chartAccounts.category);
2758
2790
  }
2759
2791
  /**
2760
- * Get new property collection filtered by active status
2792
+ * @TODO move to base collection
2761
2793
  */
2762
- getActiveProperties() {
2763
- return new PropertyCollection(this.items.filter((property) => property.isActive));
2794
+ isExpense() {
2795
+ // @TODO not used
2796
+ if (!this.chartAccounts) {
2797
+ return this.isDebit();
2798
+ }
2799
+ return CHART_ACCOUNTS_CATEGORIES.expense.includes(this.chartAccounts.category);
2764
2800
  }
2765
- getCreatedProperties() {
2766
- return new PropertyCollection(this.items.filter((property) => property.isOwn()));
2801
+ isPersonal() {
2802
+ return CHART_ACCOUNTS_CATEGORIES.personal.includes(this.chartAccounts.category);
2767
2803
  }
2768
- /**
2769
- * Get new property collection filtered by shared
2770
- */
2771
- getSharedProperties() {
2772
- return new PropertyCollection(this.items.filter((property) => !property.isOwn()));
2804
+ isInterest() {
2805
+ return this.chartAccounts.id === ChartAccountsListEnum.INTEREST_ON_LOAN;
2806
+ }
2807
+ get chartAccountsCategories() {
2808
+ switch (true) {
2809
+ case this.isPersonal():
2810
+ return CHART_ACCOUNTS_CATEGORIES.personal;
2811
+ case this.isPropertyTank():
2812
+ return CHART_ACCOUNTS_CATEGORIES.property;
2813
+ case this.isSoleTank():
2814
+ return CHART_ACCOUNTS_CATEGORIES.sole;
2815
+ default:
2816
+ return CHART_ACCOUNTS_CATEGORIES.work;
2817
+ }
2773
2818
  }
2774
2819
  /**
2775
- * Properties that are taxed and will be included in reports (Tax summary, My tax report, e.t.c.)
2820
+ * Get transaction date
2776
2821
  */
2777
- getTaxInclusive() {
2778
- return this.create(this.items.filter((property) => property.category.isTaxInclusive));
2779
- }
2780
- getUnsold() {
2781
- return this.create(this.items.filter((property) => !property.isSold()));
2822
+ getDate() {
2823
+ return this.date;
2782
2824
  }
2783
2825
  /**
2784
- * Get total purchase price for all properties in the collection
2826
+ * Check if transaction type is vehicle
2785
2827
  */
2786
- get purchasePrice() {
2787
- return this.sumBy('purchasePrice');
2828
+ isVehicleTransaction() {
2829
+ return this.chartAccounts.isVehicleExpense();
2788
2830
  }
2789
- get growthPercent() {
2790
- return this.sumBy('growthPercent');
2831
+ get taxFreeComponent() {
2832
+ return this.getMetadataFieldValue(ChartAccountsMetadataListEnum.TAX_FREE_COMPONENT);
2791
2833
  }
2792
- get marketValue() {
2793
- return this.sumBy('marketValue');
2834
+ get frankingCredit() {
2835
+ return this.getMetadataFieldValue(ChartAccountsMetadataListEnum.FRANKING_CREDIT);
2794
2836
  }
2795
- get firstForecastYear() {
2796
- return this.items.reduce((min, property) => {
2797
- const current = property.firstForecastYear;
2798
- return min > current ? current : min;
2799
- }, new FinancialYear().year);
2837
+ get eligibleForReduction() {
2838
+ return this.getMetadataFieldValue(ChartAccountsMetadataListEnum.ELIGIBLE_FOR_REDUCTION);
2800
2839
  }
2801
- get marketValueGrowth() {
2802
- return (this.marketValue - this.purchasePrice) / this.purchasePrice;
2840
+ get untaxedElement() {
2841
+ return this.getMetadataFieldValue(ChartAccountsMetadataListEnum.UNTAXED_ELEMENT);
2803
2842
  }
2804
2843
  /**
2805
- * list of properties
2844
+ * Check if transaction reconcile operation if TRANSFER
2845
+ * @TODO bad usage of get (and all is* methods), getter should sound like a noun
2806
2846
  */
2807
- getCGTApplicable() {
2808
- return this.create(this.items.filter((property) => property.isCGTApplicable()));
2809
- }
2810
- getOwnerOccupiedProperties() {
2811
- return new PropertyCollection(this.items.filter((property) => property.category.isOwnerOccupied()));
2812
- }
2813
- get earliestContractDate() {
2814
- return this.items.reduce((min, property) => {
2815
- return min < property.contractDate ? min : property.contractDate;
2816
- }, new FinancialYear(new Date()).startDate);
2847
+ get isTransfer() {
2848
+ return this.operation === TransactionOperationEnum.TRANSFER;
2817
2849
  }
2818
- /**
2819
- * Get list of unique property categories from collection
2820
- */
2821
- getCategories() {
2822
- return uniqBy(this.items.map((property) => property.category), 'id');
2850
+ isFindAndMatch() {
2851
+ return this.operation === TransactionOperationEnum.FIND_AND_MATCH;
2823
2852
  }
2824
- /**
2825
- * Get property with the highest growth percent
2826
- */
2827
- getBestPerformanceGrowthProperty() {
2828
- return this.items.reduce((max, current) => {
2829
- return max.growthPercent < current.growthPercent ? current : max;
2830
- }, this.first);
2853
+ isMatchInvoice() {
2854
+ return this.operation === TransactionOperationEnum.MATCH_INVOICE;
2831
2855
  }
2832
- /**
2833
- * Get property with the lowest tax position
2834
- */
2835
- getBestPerformanceTaxProperty(transactions, depreciations) {
2836
- const transactionsByProperty = transactions.groupBy('property.id');
2837
- const depreciationsByProperty = depreciations.groupBy('property.id');
2838
- return this.items.reduce((min, current) => {
2839
- const minTaxPosition = min.getTaxPosition(transactionsByProperty.get(min.id), depreciationsByProperty.get(min.id));
2840
- const currentTaxPosition = current.getTaxPosition(transactionsByProperty.get(current.id), depreciationsByProperty.get(current.id));
2841
- return minTaxPosition > currentTaxPosition ? current : min;
2842
- }, this.first);
2856
+ get debit() {
2857
+ return this.isDebit() ? Math.abs(this.grossAmount) : 0;
2843
2858
  }
2844
- /**
2845
- * Show best performance properties first
2846
- * https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/217677997/Property+Tank+Dashboard
2847
- */
2848
- sortByBestPerformance(transactions, depreciations) {
2849
- const activeProperties = this.getActiveProperties();
2850
- // nothing to sort when no active properties
2851
- if (!activeProperties.length) {
2852
- return this;
2853
- }
2854
- const bestProperties = uniqBy(this.create([
2855
- activeProperties.getBestPerformanceGrowthProperty(),
2856
- activeProperties.getBestPerformanceTaxProperty(transactions, depreciations)
2857
- ]).toArray(), 'id');
2858
- const newItems = this.remove(bestProperties).toArray();
2859
- newItems.unshift(...bestProperties);
2860
- return this.create(newItems);
2859
+ get credit() {
2860
+ return this.isCredit() ? Math.abs(this.grossAmount) : 0;
2861
2861
  }
2862
- }
2863
-
2864
- class PropertyCategoryMovementCollection extends Collection {
2865
2862
  /**
2866
- * @TODO TT-2355 Alex refactor propertyForecast, use separated api (then I can remove property from param)
2863
+ * Get value of transaction metadata field
2864
+ * @param field for which value should be returned
2865
+ * @Todo modify 'metadata' property from array to Collection
2867
2866
  */
2868
- getByForecast(property, forecast) {
2869
- const financialYear = new FinancialYear(forecast.financialYear);
2870
- return this.filterBy('property.id', property.id).filter((movement) => {
2871
- return movement.fromDate <= financialYear.endDate && !movement.toDate || movement.toDate >= financialYear.startDate;
2872
- });
2867
+ getMetadataFieldValue(field) {
2868
+ var _a;
2869
+ return +((_a = this.metadata.find((transactionMetadata) => {
2870
+ return transactionMetadata.chartAccountsMetadata.id === field;
2871
+ })) === null || _a === void 0 ? void 0 : _a.value) || 0;
2873
2872
  }
2874
- hasCategory(categoryId) {
2875
- return !!this.findBy('propertyCategory.id', categoryId);
2873
+ isCash() {
2874
+ return this.source === TransactionSourceEnum.CASH;
2876
2875
  }
2877
- }
2878
-
2879
- class PropertyShareCollection extends Collection {
2880
2876
  /**
2881
- * Get list of incoming property shares
2882
- * (initiated not by current user)
2883
- * @TODO Alex: rename
2877
+ * Create Depreciation instance based on Transaction
2884
2878
  */
2885
- getIncoming() {
2886
- return this.filter((propertyShare) => {
2887
- var _a;
2888
- return ((_a = propertyShare.user) === null || _a === void 0 ? void 0 : _a.isLoggedIn()) && propertyShare.isPending() && propertyShare.property.user.id !== +localStorage.getItem('userId');
2879
+ toDepreciation() {
2880
+ return plainToClass(Depreciation, {
2881
+ date: this.date,
2882
+ amount: this.amount,
2883
+ chartAccounts: this.chartAccounts,
2884
+ description: this.description,
2885
+ type: DepreciationTypeEnum.PLANT_EQUIPMENT,
2886
+ claimPercent: this.claimPercent,
2887
+ property: this.property,
2888
+ calculation: this.property ? this.property.depreciationCalculation : DepreciationCalculationEnum.PRIME_COST
2889
2889
  });
2890
2890
  }
2891
2891
  /**
2892
- * Get list of outcoming property shares
2893
- * (initiated by current user)
2894
- * @TODO Alex: rename
2892
+ * Check if transaction is completely allocated
2895
2893
  */
2896
- getOutcoming() {
2897
- return this.filter((propertyShare) => { var _a; return !((_a = propertyShare.user) === null || _a === void 0 ? void 0 : _a.isLoggedIn()); });
2898
- }
2899
- }
2900
-
2901
- /**
2902
- * Enum with symbols based on depreciation LVP asset type
2903
- */
2904
- var DepreciationLvpAssetTypeEnum;
2905
- (function (DepreciationLvpAssetTypeEnum) {
2906
- DepreciationLvpAssetTypeEnum["PRIOR_YEARS"] = "A";
2907
- DepreciationLvpAssetTypeEnum["FIRST_YEAR"] = "L";
2908
- DepreciationLvpAssetTypeEnum["WRITTEN_OFF"] = "W";
2909
- })(DepreciationLvpAssetTypeEnum || (DepreciationLvpAssetTypeEnum = {}));
2910
-
2911
- class DepreciationCapitalProject extends DepreciationCapitalProject$1 {
2912
- }
2913
- __decorate([
2914
- Type(() => Date)
2915
- ], DepreciationCapitalProject.prototype, "effectiveDate", void 0);
2916
-
2917
- class DepreciationForecast extends DepreciationForecast$1 {
2918
- get dailyClaimAmount() {
2919
- return this.claimAmount / this.daysApplied;
2920
- }
2921
- get daysApplied() {
2922
- return moment$1(this.toDate).diff(moment$1(this.fromDate), 'days');
2894
+ isAllocated(allocations) {
2895
+ return this.netAmount === this.getAllocatedAmount(allocations);
2923
2896
  }
2924
- getDaysByMonth(month) {
2925
- // @TODO find a better place
2926
- const year = this.financialYear - (month > 5 ? 1 : 0);
2927
- // forecast date intersect by month
2928
- const range = new DateRange(this.fromDate, this.toDate).intersect(new DateRange(new Date(year, month, 1), new Date(year, month + 1, 0)));
2929
- return range ? range.duration('days') + 1 : 0;
2897
+ getAllocatedAmount(allocations) {
2898
+ return allocations.filterBy('transaction.id', this.id).sumBy('amount');
2930
2899
  }
2931
- get claimOpenBalance() {
2932
- return this.openBalance * this.claimRate;
2900
+ getAllocatedClaimAmount(allocations) {
2901
+ let coef = 1;
2902
+ if (this.isSoleTank() && this.isIncome() && this.isGST) {
2903
+ coef = ChartAccounts.GSTCoefficient;
2904
+ }
2905
+ return this.getAllocatedAmount(allocations) * this.claimRatio / coef;
2933
2906
  }
2934
- get claimCloseBalance() {
2935
- return this.closeBalance * this.claimRate;
2907
+ getUnallocatedAmount(allocations) {
2908
+ return this.netAmount - this.getAllocatedAmount(allocations);
2936
2909
  }
2937
- get claimAmount() {
2938
- return this.amount * this.claimRate;
2910
+ /**
2911
+ * Total transaction amount including taxes and other additional amounts
2912
+ */
2913
+ get grossAmount() {
2914
+ let grossAmount = super.grossAmount + this.tax;
2915
+ if (this.isExpense()) {
2916
+ return grossAmount;
2917
+ }
2918
+ // salary included transactions affect parent transaction amount and as a result grossAmount, skip to avoid double sum
2919
+ grossAmount += new Collection(this.transactions)
2920
+ .filter((t) => { var _a; return !((_a = t.chartAccounts) === null || _a === void 0 ? void 0 : _a.isSalaryIncluded()); })
2921
+ .sumBy('amount', true);
2922
+ if (this.isWorkTank()) {
2923
+ grossAmount += this.frankingCredit - this.taxFreeComponent - this.eligibleForReduction;
2924
+ }
2925
+ return +(Math.round(grossAmount * 100) / 100).toFixed(2);
2939
2926
  }
2940
- get claimRate() {
2941
- return this.claimPercent / 100;
2927
+ /**
2928
+ * @TODO vik confusing logic demanded by Nicole, we need a better ux to fix it
2929
+ * netAmount matches received payment (bankTransaction amount), includes gst and salary included adjustments
2930
+ * ie user received 1000$ salary including 100$ tips. NetAmount=1000$, amount=900$, tips=100$
2931
+ */
2932
+ get netAmount() {
2933
+ return new Collection(this.transactions)
2934
+ .filter((t) => { var _a; return (_a = t.chartAccounts) === null || _a === void 0 ? void 0 : _a.isSalaryIncluded(); })
2935
+ .sumBy('amount') + this.amountWithGst;
2942
2936
  }
2943
- getClaimAmountByMonth(month) {
2944
- return this.getDaysByMonth(month) * this.dailyClaimAmount;
2937
+ /**
2938
+ * most of the transactions could have only positive or negative amount depends on chartAccounts, so we ignore
2939
+ * user's choice and transform amount, but there are exceptions like advance (negative or positive amount)
2940
+ */
2941
+ ignoreSign() {
2942
+ var _a;
2943
+ return !(((_a = this.chartAccounts) === null || _a === void 0 ? void 0 : _a.id) in ChartAccountsKeepSign);
2945
2944
  }
2946
2945
  }
2947
-
2948
- /**
2949
- * Enum with income amount types (Net or Gross)
2950
- */
2951
- var IncomeAmountTypeEnum;
2952
- (function (IncomeAmountTypeEnum) {
2953
- IncomeAmountTypeEnum[IncomeAmountTypeEnum["NET"] = 0] = "NET";
2954
- IncomeAmountTypeEnum[IncomeAmountTypeEnum["GROSS"] = 1] = "GROSS";
2955
- })(IncomeAmountTypeEnum || (IncomeAmountTypeEnum = {}));
2946
+ __decorate([
2947
+ Type(() => Transaction)
2948
+ ], Transaction.prototype, "transactions", void 0);
2949
+ __decorate([
2950
+ Type(() => Property)
2951
+ ], Transaction.prototype, "property", void 0);
2952
+ __decorate([
2953
+ Type(() => TransactionReceipt)
2954
+ ], Transaction.prototype, "receipt", void 0);
2955
+ __decorate([
2956
+ Type(() => ChartAccounts)
2957
+ ], Transaction.prototype, "chartAccounts", void 0);
2958
+ __decorate([
2959
+ Type(() => IncomeSource)
2960
+ ], Transaction.prototype, "incomeSource", void 0);
2961
+ __decorate([
2962
+ Type(() => TransactionMetadata)
2963
+ ], Transaction.prototype, "metadata", void 0);
2964
+ __decorate([
2965
+ Type(() => Transaction)
2966
+ ], Transaction.prototype, "transfer", void 0);
2967
+ __decorate([
2968
+ Type(() => Loan)
2969
+ ], Transaction.prototype, "loan", void 0);
2970
+ __decorate([
2971
+ Type(() => Date)
2972
+ ], Transaction.prototype, "date", void 0);
2973
+ __decorate([
2974
+ Type(() => TransactionAllocation)
2975
+ ], Transaction.prototype, "allocations", void 0);
2956
2976
 
2957
2977
  var TransactionCategoryEnum;
2958
2978
  (function (TransactionCategoryEnum) {
@@ -3852,10 +3872,54 @@ class SoleInvoiceCollection extends Collection {
3852
3872
  }
3853
3873
  }
3854
3874
 
3875
+ var ServicePriceTypeEnum;
3876
+ (function (ServicePriceTypeEnum) {
3877
+ ServicePriceTypeEnum[ServicePriceTypeEnum["DEPRECATED"] = 0] = "DEPRECATED";
3878
+ ServicePriceTypeEnum[ServicePriceTypeEnum["MONTHLY"] = 1] = "MONTHLY";
3879
+ ServicePriceTypeEnum[ServicePriceTypeEnum["MONTHLY_PACKAGE"] = 2] = "MONTHLY_PACKAGE";
3880
+ ServicePriceTypeEnum[ServicePriceTypeEnum["YEARLY"] = 3] = "YEARLY";
3881
+ ServicePriceTypeEnum[ServicePriceTypeEnum["YEARLY_PACKAGE"] = 4] = "YEARLY_PACKAGE";
3882
+ })(ServicePriceTypeEnum || (ServicePriceTypeEnum = {}));
3883
+
3884
+ /**
3885
+ * @TODO vik refactor
3886
+ */
3855
3887
  class ServicePriceCollection extends Collection {
3856
3888
  getActive() {
3857
3889
  return this.filterBy('isActive', true);
3858
3890
  }
3891
+ get monthly() {
3892
+ return this.filterBy('type', ServicePriceTypeEnum.MONTHLY);
3893
+ }
3894
+ get monthlyPackage() {
3895
+ return this.filterBy('type', ServicePriceTypeEnum.MONTHLY_PACKAGE);
3896
+ }
3897
+ get monthlyPackageSum() {
3898
+ const property = this.monthlyPackage.findBy('product.id', ServiceProductIdEnum.PROPERTIES);
3899
+ // @TODO move to const
3900
+ return this.monthlyPackage.sumBy('amount') + property.amount * 4;
3901
+ }
3902
+ get annual() {
3903
+ return this.filterBy('type', ServicePriceTypeEnum.YEARLY);
3904
+ }
3905
+ get annualPackage() {
3906
+ return this.filterBy('type', ServicePriceTypeEnum.YEARLY_PACKAGE);
3907
+ }
3908
+ get annualPackageSum() {
3909
+ const property = this.annualPackage.findBy('product.id', ServiceProductIdEnum.PROPERTIES);
3910
+ // @TODO move to const
3911
+ return this.annualPackage.sumBy('amount') + property.amount * 4;
3912
+ }
3913
+ getProperty(isAnnual, isPackage) {
3914
+ let type;
3915
+ if (isAnnual) {
3916
+ type = isPackage ? ServicePriceTypeEnum.YEARLY_PACKAGE : ServicePriceTypeEnum.YEARLY;
3917
+ }
3918
+ else {
3919
+ type = isPackage ? ServicePriceTypeEnum.MONTHLY_PACKAGE : ServicePriceTypeEnum.MONTHLY;
3920
+ }
3921
+ return this.filterBy('type', type).findBy('product.id', ServiceProductIdEnum.PROPERTIES);
3922
+ }
3859
3923
  }
3860
3924
 
3861
3925
  class ServiceProductCollection extends Collection {
@@ -4791,220 +4855,207 @@ class UserEventTypeCollection extends Collection {
4791
4855
 
4792
4856
  // @TODO Alex move here all collections
4793
4857
 
4794
- // @TODO Alex: refactor: move here allocations methods, netAmount = amount, grossAmount calculation, remove unused methods, etc.
4795
- class Transaction extends Transaction$1 {
4858
+ class ServiceSubscription extends ServiceSubscription$1 {
4796
4859
  constructor() {
4797
4860
  super(...arguments);
4798
- // list of child transactions (fees)
4799
- this.transactions = [];
4800
- this.metadata = [];
4801
- this.allocations = [];
4802
- this.tax = 0;
4803
- this.operation = TransactionOperationEnum.FIND_AND_MATCH;
4804
- this.claimPercent = 100;
4805
- this.amount = 0;
4806
- }
4807
- isDebit() {
4808
- return this.type === TransactionTypeEnum.DEBIT;
4809
- }
4810
- isCredit() {
4811
- return this.type === TransactionTypeEnum.CREDIT;
4812
- }
4813
- /**
4814
- * @TODO move to base collection
4815
- */
4816
- isIncome() {
4817
- // @TODO not used
4818
- if (!this.chartAccounts) {
4819
- return this.isCredit();
4820
- }
4821
- return CHART_ACCOUNTS_CATEGORIES.income.includes(this.chartAccounts.category);
4822
- }
4823
- /**
4824
- * @TODO move to base collection
4825
- */
4826
- isExpense() {
4827
- // @TODO not used
4828
- if (!this.chartAccounts) {
4829
- return this.isDebit();
4830
- }
4831
- return CHART_ACCOUNTS_CATEGORIES.expense.includes(this.chartAccounts.category);
4861
+ // Number of days after which the trial time will be expired
4862
+ this.lastTrialDays = 4;
4832
4863
  }
4833
- isPersonal() {
4834
- return CHART_ACCOUNTS_CATEGORIES.personal.includes(this.chartAccounts.category);
4864
+ get isTrial() {
4865
+ return !this.stripeId;
4835
4866
  }
4836
- isInterest() {
4837
- return this.chartAccounts.id === ChartAccountsListEnum.INTEREST_ON_LOAN;
4867
+ get isPaid() {
4868
+ return !!this.stripeId;
4838
4869
  }
4839
- get chartAccountsCategories() {
4840
- switch (true) {
4841
- case this.isPersonal():
4842
- return CHART_ACCOUNTS_CATEGORIES.personal;
4843
- case this.isPropertyTank():
4844
- return CHART_ACCOUNTS_CATEGORIES.property;
4845
- case this.isSoleTank():
4846
- return CHART_ACCOUNTS_CATEGORIES.sole;
4847
- default:
4848
- return CHART_ACCOUNTS_CATEGORIES.work;
4849
- }
4870
+ get price() {
4871
+ return this.items.reduce((sum, item) => sum + item.total, 0);
4850
4872
  }
4851
4873
  /**
4852
- * Get transaction date
4874
+ * get title of subscription
4853
4875
  */
4854
- getDate() {
4855
- return this.date;
4876
+ get title() {
4877
+ return this.items.map((item) => item.price.product.title).join(' + ');
4878
+ // return this.isTrial ? 'Trial period' : this.items.map((item) => item.price.product.title).join(' + ');
4856
4879
  }
4857
4880
  /**
4858
- * Check if transaction type is vehicle
4881
+ * A subscription is considered active if the end date has not yet arrived and its status is "Active" or "Past due"
4859
4882
  */
4860
- isVehicleTransaction() {
4861
- return this.chartAccounts.isVehicleExpense();
4862
- }
4863
- get taxFreeComponent() {
4864
- return this.getMetadataFieldValue(ChartAccountsMetadataListEnum.TAX_FREE_COMPONENT);
4865
- }
4866
- get frankingCredit() {
4867
- return this.getMetadataFieldValue(ChartAccountsMetadataListEnum.FRANKING_CREDIT);
4868
- }
4869
- get eligibleForReduction() {
4870
- return this.getMetadataFieldValue(ChartAccountsMetadataListEnum.ELIGIBLE_FOR_REDUCTION);
4883
+ get isActive() {
4884
+ const isExpired = new Date(this.endDate).getTime() < new Date().getTime();
4885
+ return !isExpired && ([ServiceSubscriptionStatusEnum.ACTIVE, ServiceSubscriptionStatusEnum.PAST_DUE].includes(this.status));
4871
4886
  }
4872
- get untaxedElement() {
4873
- return this.getMetadataFieldValue(ChartAccountsMetadataListEnum.UNTAXED_ELEMENT);
4887
+ get daysRemain() {
4888
+ const daysRemains = Math.round((new Date(this.endDate).getTime() - new Date().getTime()) / (1000 * 3600 * 24));
4889
+ return daysRemains > 0 ? daysRemains : 0;
4874
4890
  }
4875
4891
  /**
4876
- * Check if transaction reconcile operation if TRANSFER
4877
- * @TODO bad usage of get (and all is* methods), getter should sound like a noun
4892
+ * Check if trial expired
4878
4893
  */
4879
- get isTransfer() {
4880
- return this.operation === TransactionOperationEnum.TRANSFER;
4881
- }
4882
- isFindAndMatch() {
4883
- return this.operation === TransactionOperationEnum.FIND_AND_MATCH;
4894
+ isTrialExpired() {
4895
+ return this.daysRemain && this.daysRemain <= 0;
4884
4896
  }
4885
- isMatchInvoice() {
4886
- return this.operation === TransactionOperationEnum.MATCH_INVOICE;
4897
+ isTrialExpiring() {
4898
+ return this.daysRemain > 0 && this.daysRemain <= this.lastTrialDays;
4887
4899
  }
4888
- get debit() {
4889
- return this.isDebit() ? Math.abs(this.grossAmount) : 0;
4900
+ isRenewable() {
4901
+ return !this.isTrial && this.isActive;
4890
4902
  }
4891
- get credit() {
4892
- return this.isCredit() ? Math.abs(this.grossAmount) : 0;
4903
+ getItems() {
4904
+ return new SubscriptionItemCollection(this.items);
4893
4905
  }
4894
4906
  /**
4895
- * Get value of transaction metadata field
4896
- * @param field for which value should be returned
4897
- * @Todo modify 'metadata' property from array to Collection
4907
+ * @TODO move to collection
4898
4908
  */
4899
- getMetadataFieldValue(field) {
4900
- var _a;
4901
- return +((_a = this.metadata.find((transactionMetadata) => {
4902
- return transactionMetadata.chartAccountsMetadata.id === field;
4903
- })) === null || _a === void 0 ? void 0 : _a.value) || 0;
4909
+ get workTankItem() {
4910
+ return this.items.find((item) => item.price.product.isWorkTank());
4904
4911
  }
4905
- isCash() {
4906
- return this.source === TransactionSourceEnum.CASH;
4912
+ get soleTankItem() {
4913
+ return this.items.find((item) => item.price.product.isSoleTank());
4907
4914
  }
4908
- /**
4909
- * Create Depreciation instance based on Transaction
4910
- */
4911
- toDepreciation() {
4912
- return plainToClass(Depreciation, {
4913
- date: this.date,
4914
- amount: this.amount,
4915
- chartAccounts: this.chartAccounts,
4916
- description: this.description,
4917
- type: DepreciationTypeEnum.PLANT_EQUIPMENT,
4918
- claimPercent: this.claimPercent,
4919
- property: this.property,
4920
- calculation: this.property ? this.property.depreciationCalculation : DepreciationCalculationEnum.PRIME_COST
4915
+ get propertyTankItem() {
4916
+ return this.items.find((item) => item.price.product.isProperties());
4917
+ }
4918
+ hasPropertyTank() {
4919
+ return !!this.items.find((subscriptionItem) => {
4920
+ return subscriptionItem.price.product.role.includes(UserRolesEnum.PROPERTY_TANK);
4921
+ });
4922
+ }
4923
+ hasWorkTank() {
4924
+ return !!this.items.find((subscriptionItem) => {
4925
+ return subscriptionItem.price.product.role.includes(UserRolesEnum.WORK_TANK);
4921
4926
  });
4922
4927
  }
4923
4928
  /**
4924
- * Check if transaction is completely allocated
4929
+ * bought before price updates, active for some time to let customer select a new plan
4930
+ * impossible to update, only prolong or buy new
4925
4931
  */
4926
- isAllocated(allocations) {
4927
- return this.netAmount === this.getAllocatedAmount(allocations);
4928
- }
4929
- getAllocatedAmount(allocations) {
4930
- return allocations.filterBy('transaction.id', this.id).sumBy('amount');
4931
- }
4932
- getAllocatedClaimAmount(allocations) {
4933
- let coef = 1;
4934
- if (this.isSoleTank() && this.isIncome() && this.isGST) {
4935
- coef = ChartAccounts.GSTCoefficient;
4936
- }
4937
- return this.getAllocatedAmount(allocations) * this.claimRatio / coef;
4938
- }
4939
- getUnallocatedAmount(allocations) {
4940
- return this.netAmount - this.getAllocatedAmount(allocations);
4932
+ isArchived() {
4933
+ // subscription with at least one archived product considered as archived
4934
+ return !!this.items.filter((item) => item.price.product.isArchived()).length;
4941
4935
  }
4942
4936
  /**
4943
- * Total transaction amount including taxes and other additional amounts
4937
+ * Case when payment was failed, but user has a time to update payment method
4944
4938
  */
4945
- get grossAmount() {
4946
- let grossAmount = super.grossAmount + this.tax;
4947
- if (this.isExpense()) {
4948
- return grossAmount;
4949
- }
4950
- // salary included transactions affect parent transaction amount and as a result grossAmount, skip to avoid double sum
4951
- grossAmount += new Collection(this.transactions)
4952
- .filter((t) => { var _a; return !((_a = t.chartAccounts) === null || _a === void 0 ? void 0 : _a.isSalaryIncluded()); })
4953
- .sumBy('amount', true);
4954
- if (this.isWorkTank()) {
4955
- grossAmount += this.frankingCredit - this.taxFreeComponent - this.eligibleForReduction;
4956
- }
4957
- return +(Math.round(grossAmount * 100) / 100).toFixed(2);
4939
+ isPastDue() {
4940
+ return this.status === ServiceSubscriptionStatusEnum.PAST_DUE;
4958
4941
  }
4959
4942
  /**
4960
- * @TODO vik confusing logic demanded by Nicole, we need a better ux to fix it
4961
- * netAmount matches received payment (bankTransaction amount), includes gst and salary included adjustments
4962
- * ie user received 1000$ salary including 100$ tips. NetAmount=1000$, amount=900$, tips=100$
4943
+ * Check if current subscription has provided subscription item
4963
4944
  */
4964
- get netAmount() {
4965
- return new Collection(this.transactions)
4966
- .filter((t) => { var _a; return (_a = t.chartAccounts) === null || _a === void 0 ? void 0 : _a.isSalaryIncluded(); })
4967
- .sumBy('amount') + this.amountWithGst;
4945
+ hasItem(itemToCheck) {
4946
+ return !!this.items.find((item) => item.price.id === itemToCheck.price.id);
4947
+ }
4948
+ hasProduct(product) {
4949
+ return !!this.items.find((item) => item.price.product.id === product.id);
4950
+ }
4951
+ isPackage() {
4952
+ return this.items.length === ServiceProduct.quantity;
4968
4953
  }
4969
4954
  /**
4970
- * most of the transactions could have only positive or negative amount depends on chartAccounts, so we ignore
4971
- * user's choice and transform amount, but there are exceptions like advance (negative or positive amount)
4955
+ * Recommended number of properties to buy,
4956
+ * based on the property service product and the number of properties the user has
4972
4957
  */
4973
- ignoreSign() {
4974
- var _a;
4975
- return !(((_a = this.chartAccounts) === null || _a === void 0 ? void 0 : _a.id) in ChartAccountsKeepSign);
4958
+ getRecommendedPropertiesQty(propertyItem, propertiesQty) {
4959
+ const min = propertyItem.price.product.minQty;
4960
+ return Math.max(min, propertiesQty);
4976
4961
  }
4977
4962
  }
4978
4963
  __decorate([
4979
- Type(() => Transaction)
4980
- ], Transaction.prototype, "transactions", void 0);
4981
- __decorate([
4982
- Type(() => Property)
4983
- ], Transaction.prototype, "property", void 0);
4964
+ Type(() => Date)
4965
+ ], ServiceSubscription.prototype, "startDate", void 0);
4984
4966
  __decorate([
4985
- Type(() => TransactionReceipt)
4986
- ], Transaction.prototype, "receipt", void 0);
4967
+ Type(() => Date)
4968
+ ], ServiceSubscription.prototype, "endDate", void 0);
4987
4969
  __decorate([
4988
- Type(() => ChartAccounts)
4989
- ], Transaction.prototype, "chartAccounts", void 0);
4970
+ Type(() => ServiceSubscriptionItem)
4971
+ ], ServiceSubscription.prototype, "items", void 0);
4972
+
4973
+ class SoleBusinessAllocation extends SoleBusinessAllocation$1 {
4974
+ }
4990
4975
  __decorate([
4991
- Type(() => IncomeSource)
4992
- ], Transaction.prototype, "incomeSource", void 0);
4976
+ Type(() => BankAccount)
4977
+ ], SoleBusinessAllocation.prototype, "bankAccount", void 0);
4993
4978
  __decorate([
4994
- Type(() => TransactionMetadata)
4995
- ], Transaction.prototype, "metadata", void 0);
4979
+ Type(() => SoleBusiness)
4980
+ ], SoleBusinessAllocation.prototype, "business", void 0);
4996
4981
  __decorate([
4997
- Type(() => Transaction)
4998
- ], Transaction.prototype, "transfer", void 0);
4982
+ Transform(({ value }) => value || 100),
4983
+ Expose()
4984
+ ], SoleBusinessAllocation.prototype, "percent", void 0);
4985
+
4986
+ class SoleBusinessLossOffsetRule extends SoleBusinessLossOffsetRule$1 {
4987
+ }
4999
4988
  __decorate([
5000
- Type(() => Loan)
5001
- ], Transaction.prototype, "loan", void 0);
4989
+ Type(() => SoleBusinessLossOffsetRule)
4990
+ ], SoleBusinessLossOffsetRule.prototype, "parent", void 0);
4991
+
4992
+ /**
4993
+ * If a sole trader business makes a tax loss in a current year, you can generally carry forward that loss and offset profit in future years.
4994
+ * https://taxtank.atlassian.net/wiki/spaces/TAXTANK/pages/4641357930/Rules+when+a+business+makes+a+loss+Tax+Summary#Offsetting-current-year-business-losses
4995
+ */
4996
+ class SoleBusinessLoss extends SoleBusinessLoss$1 {
4997
+ constructor() {
4998
+ super(...arguments);
4999
+ this.openBalance = 0;
5000
+ this.financialYear = new FinancialYear().year;
5001
+ }
5002
+ get hasOffset() {
5003
+ return !!this.offsetRule;
5004
+ }
5005
+ }
5002
5006
  __decorate([
5003
- Type(() => Date)
5004
- ], Transaction.prototype, "date", void 0);
5007
+ Type(() => SoleBusiness)
5008
+ ], SoleBusinessLoss.prototype, "business", void 0);
5005
5009
  __decorate([
5006
- Type(() => TransactionAllocation)
5007
- ], Transaction.prototype, "allocations", void 0);
5010
+ Type(() => SoleBusinessLossOffsetRule)
5011
+ ], SoleBusinessLoss.prototype, "offsetRule", void 0);
5012
+
5013
+ var MyAccountHistoryInitiatedByEnum;
5014
+ (function (MyAccountHistoryInitiatedByEnum) {
5015
+ MyAccountHistoryInitiatedByEnum[MyAccountHistoryInitiatedByEnum["OWNER"] = 0] = "OWNER";
5016
+ MyAccountHistoryInitiatedByEnum[MyAccountHistoryInitiatedByEnum["ACCOUNTANT"] = 1] = "ACCOUNTANT";
5017
+ })(MyAccountHistoryInitiatedByEnum || (MyAccountHistoryInitiatedByEnum = {}));
5018
+
5019
+ var MyAccountHistoryStatusEnum;
5020
+ (function (MyAccountHistoryStatusEnum) {
5021
+ MyAccountHistoryStatusEnum[MyAccountHistoryStatusEnum["SUCCESS"] = 0] = "SUCCESS";
5022
+ MyAccountHistoryStatusEnum[MyAccountHistoryStatusEnum["ERROR"] = 1] = "ERROR";
5023
+ })(MyAccountHistoryStatusEnum || (MyAccountHistoryStatusEnum = {}));
5024
+
5025
+ var MyAccountHistoryTypeEnum;
5026
+ (function (MyAccountHistoryTypeEnum) {
5027
+ MyAccountHistoryTypeEnum[MyAccountHistoryTypeEnum["REVIEW"] = 0] = "REVIEW";
5028
+ MyAccountHistoryTypeEnum[MyAccountHistoryTypeEnum["UPGRADE_PLAN"] = 1] = "UPGRADE_PLAN";
5029
+ MyAccountHistoryTypeEnum[MyAccountHistoryTypeEnum["UPLOAD_DOCUMENT"] = 2] = "UPLOAD_DOCUMENT";
5030
+ })(MyAccountHistoryTypeEnum || (MyAccountHistoryTypeEnum = {}));
5031
+
5032
+ class MyAccountHistory {
5033
+ }
5034
+
5035
+ class Occupation extends Occupation$1 {
5036
+ }
5037
+
5038
+ /**
5039
+ * role hierarchy
5040
+ */
5041
+ const USER_ROLES = {
5042
+ ROLE_FIRM_OWNER: [UserRolesEnum.FIRM_OWNER, UserRolesEnum.FIRM_MANAGER, UserRolesEnum.ACCOUNTANT, UserRolesEnum.ADVISOR],
5043
+ ROLE_FIRM_MANAGER: [UserRolesEnum.FIRM_MANAGER, UserRolesEnum.ACCOUNTANT, UserRolesEnum.ADVISOR],
5044
+ ROLE_EMPLOYEE: [UserRolesEnum.ACCOUNTANT, UserRolesEnum.ADVISOR],
5045
+ ROLE_ACCOUNTANT: [UserRolesEnum.ACCOUNTANT],
5046
+ ROLE_ADVISOR: [UserRolesEnum.ADVISOR],
5047
+ ROLE_CLIENT: [UserRolesEnum.CLIENT],
5048
+ ROLE_USER_SUBSCRIPTION: [UserRolesEnum.SUBSCRIPTION],
5049
+ ROLE_USER_WORK: [UserRolesEnum.WORK_TANK],
5050
+ ROLE_USER_PROPERTY: [UserRolesEnum.PROPERTY_TANK],
5051
+ ROLE_USER_SOLE: [UserRolesEnum.SOLE_TANK],
5052
+ };
5053
+
5054
+ /**
5055
+ * Class with basic information about registering user
5056
+ */
5057
+ class UserToRegister {
5058
+ }
5008
5059
 
5009
5060
  class SoleInvoiceItem extends SoleInvoiceItem$1 {
5010
5061
  constructor() {
@@ -8990,12 +9041,6 @@ var ServicePriceRecurringIntervalEnum;
8990
9041
  ServicePriceRecurringIntervalEnum[ServicePriceRecurringIntervalEnum["YEAR"] = 4] = "YEAR";
8991
9042
  })(ServicePriceRecurringIntervalEnum || (ServicePriceRecurringIntervalEnum = {}));
8992
9043
 
8993
- var ServicePriceTypeEnum;
8994
- (function (ServicePriceTypeEnum) {
8995
- ServicePriceTypeEnum[ServicePriceTypeEnum["ONE_TIME"] = 1] = "ONE_TIME";
8996
- ServicePriceTypeEnum[ServicePriceTypeEnum["RECURRING"] = 2] = "RECURRING";
8997
- })(ServicePriceTypeEnum || (ServicePriceTypeEnum = {}));
8998
-
8999
9044
  var SpareDocumentSpareTypeEnum;
9000
9045
  (function (SpareDocumentSpareTypeEnum) {
9001
9046
  SpareDocumentSpareTypeEnum[SpareDocumentSpareTypeEnum["DOCUMENT"] = 1] = "DOCUMENT";
@@ -13307,7 +13352,7 @@ class SubscriptionService extends RestService$1 {
13307
13352
  this.endpointUri = 'service-subscriptions';
13308
13353
  this.modelClass = ServiceSubscription;
13309
13354
  this.collectionClass = ServiceSubscriptionCollection;
13310
- this.disabledMethods = ['put', 'putBatch', 'delete', 'deleteBatch'];
13355
+ this.disabledMethods = ['putBatch', 'delete', 'deleteBatch'];
13311
13356
  this.listenSubscriptions();
13312
13357
  }
13313
13358
  startTrial(subscription) {
@@ -13357,16 +13402,16 @@ class SubscriptionService extends RestService$1 {
13357
13402
  /**
13358
13403
  * Get difference between current subscription and selected new subscription
13359
13404
  */
13360
- getProrationCost(items) {
13361
- return this.http.post(`${this.environment.apiV2}/service-subscriptions/proration-cost`, items).pipe(map((prorationCost) => {
13405
+ getProrationCost(subscription) {
13406
+ return this.http.put(`${this.environment.apiV2}/service-subscriptions/${subscription.id}/proration-cost`, subscription).pipe(map((prorationCost) => {
13362
13407
  return prorationCost;
13363
13408
  }));
13364
13409
  }
13365
13410
  /**
13366
13411
  * Change subscription plan
13367
13412
  */
13368
- changeSubscription(items) {
13369
- return this.http.post(`${this.environment.apiV2}/service-subscriptions/items`, items);
13413
+ changeSubscription(subscription) {
13414
+ return this.http.put(`${this.environment.apiV2}/service-subscriptions/${subscription.id}`, subscription);
13370
13415
  }
13371
13416
  listenSubscriptions() {
13372
13417
  this.sseService.on(`serviceSubscriptions`)