mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 14:50:32 +00:00
fix: value property in inventory item details.
This commit is contained in:
@@ -59,11 +59,12 @@ export default class InventoryDetailsController extends BaseController {
|
|||||||
* @param {ICashFlowStatement} cashFlow -
|
* @param {ICashFlowStatement} cashFlow -
|
||||||
*/
|
*/
|
||||||
private transformJsonResponse(inventoryDetails) {
|
private transformJsonResponse(inventoryDetails) {
|
||||||
const { data, query } = inventoryDetails;
|
const { data, query, meta } = inventoryDetails;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: this.transfromToResponse(data),
|
data: this.transfromToResponse(data),
|
||||||
meta: this.transfromToResponse(query),
|
query: this.transfromToResponse(query),
|
||||||
|
meta: this.transfromToResponse(meta),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +79,8 @@ export default class InventoryDetailsController extends BaseController {
|
|||||||
data: inventoryDetailsTable.tableData(),
|
data: inventoryDetailsTable.tableData(),
|
||||||
columns: inventoryDetailsTable.tableColumns(),
|
columns: inventoryDetailsTable.tableColumns(),
|
||||||
},
|
},
|
||||||
meta: this.transfromToResponse(inventoryDetails.query),
|
query: this.transfromToResponse(inventoryDetails.query),
|
||||||
|
meta: this.transfromToResponse(inventoryDetails.meta),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,8 +58,9 @@ export interface IInventoryDetailsItemTransaction {
|
|||||||
valueMovement: IInventoryDetailsNumber;
|
valueMovement: IInventoryDetailsNumber;
|
||||||
|
|
||||||
quantity: IInventoryDetailsNumber;
|
quantity: IInventoryDetailsNumber;
|
||||||
value: IInventoryDetailsNumber;
|
total: IInventoryDetailsNumber;
|
||||||
cost: IInventoryDetailsNumber;
|
cost: IInventoryDetailsNumber;
|
||||||
|
value: IInventoryDetailsNumber;
|
||||||
profitMargin: IInventoryDetailsNumber;
|
profitMargin: IInventoryDetailsNumber;
|
||||||
|
|
||||||
rate: IInventoryDetailsNumber;
|
rate: IInventoryDetailsNumber;
|
||||||
@@ -74,3 +75,16 @@ export type IInventoryDetailsNode =
|
|||||||
| IInventoryDetailsItem
|
| IInventoryDetailsItem
|
||||||
| IInventoryDetailsItemTransaction;
|
| IInventoryDetailsItemTransaction;
|
||||||
export type IInventoryDetailsData = IInventoryDetailsItem[];
|
export type IInventoryDetailsData = IInventoryDetailsItem[];
|
||||||
|
|
||||||
|
|
||||||
|
export interface IInventoryItemDetailMeta {
|
||||||
|
isCostComputeRunning: boolean;
|
||||||
|
organizationName: string;
|
||||||
|
baseCurrency: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IInvetoryItemDetailDOO {
|
||||||
|
data: IInventoryDetailsData;
|
||||||
|
query: IInventoryDetailsQuery;
|
||||||
|
meta: IInventoryItemDetailMeta;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { defaultTo, sumBy, get } from 'lodash';
|
import { defaultTo, sumBy, get } from 'lodash';
|
||||||
|
import moment from 'moment';
|
||||||
import {
|
import {
|
||||||
IInventoryDetailsQuery,
|
IInventoryDetailsQuery,
|
||||||
IItem,
|
IItem,
|
||||||
@@ -18,7 +19,6 @@ import {
|
|||||||
import FinancialSheet from '../FinancialSheet';
|
import FinancialSheet from '../FinancialSheet';
|
||||||
import { transformToMapBy, transformToMapKeyValue } from 'utils';
|
import { transformToMapBy, transformToMapKeyValue } from 'utils';
|
||||||
import { filterDeep } from 'utils/deepdash';
|
import { filterDeep } from 'utils/deepdash';
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' };
|
const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' };
|
||||||
|
|
||||||
@@ -159,7 +159,8 @@ export default class InventoryDetails extends FinancialSheet {
|
|||||||
const initial = this.getNumberMeta(0);
|
const initial = this.getNumberMeta(0);
|
||||||
|
|
||||||
const mapAccumAppender = (a, b) => {
|
const mapAccumAppender = (a, b) => {
|
||||||
const total = a.runningValuation.number + b.valueMovement.number;
|
const adjusmtent = b.direction === 'OUT' ? -1 : 1;
|
||||||
|
const total = a.runningValuation.number + b.cost.number * adjusmtent;
|
||||||
const totalMeta = this.getNumberMeta(total, { excerptZero: false });
|
const totalMeta = this.getNumberMeta(total, { excerptZero: false });
|
||||||
const accum = { ...b, runningValuation: totalMeta };
|
const accum = { ...b, runningValuation: totalMeta };
|
||||||
|
|
||||||
@@ -182,19 +183,22 @@ export default class InventoryDetails extends FinancialSheet {
|
|||||||
item: IItem,
|
item: IItem,
|
||||||
transaction: IInventoryTransaction
|
transaction: IInventoryTransaction
|
||||||
): IInventoryDetailsItemTransaction {
|
): IInventoryDetailsItemTransaction {
|
||||||
const value = transaction.quantity * transaction.rate;
|
const total = transaction.quantity * transaction.rate;
|
||||||
const amountMovement = R.curry(this.adjustAmountMovement)(
|
const amountMovement = R.curry(this.adjustAmountMovement)(
|
||||||
transaction.direction
|
transaction.direction
|
||||||
);
|
);
|
||||||
// Quantity movement.
|
// Quantity movement.
|
||||||
const quantityMovement = amountMovement(transaction.quantity);
|
const quantityMovement = amountMovement(transaction.quantity);
|
||||||
const valueMovement = amountMovement(value);
|
const cost = defaultTo(transaction?.costLotAggregated.cost, 0);
|
||||||
|
|
||||||
// Profit margin.
|
// Profit margin.
|
||||||
const profitMargin = Math.max(
|
const profitMargin = total - cost;
|
||||||
value - transaction.costLotAggregated.cost,
|
|
||||||
0
|
// Value from computed cost in `OUT` or from total sell price in `IN` transaction.
|
||||||
);
|
const value = transaction.direction === 'OUT' ? cost : total;
|
||||||
|
|
||||||
|
// Value movement depends on transaction direction.
|
||||||
|
const valueMovement = amountMovement(value);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nodeType: INodeTypes.TRANSACTION,
|
nodeType: INodeTypes.TRANSACTION,
|
||||||
@@ -207,10 +211,11 @@ export default class InventoryDetails extends FinancialSheet {
|
|||||||
valueMovement: this.getNumberMeta(valueMovement),
|
valueMovement: this.getNumberMeta(valueMovement),
|
||||||
|
|
||||||
quantity: this.getNumberMeta(transaction.quantity),
|
quantity: this.getNumberMeta(transaction.quantity),
|
||||||
value: this.getNumberMeta(value),
|
total: this.getNumberMeta(total),
|
||||||
|
|
||||||
rate: this.getNumberMeta(transaction.rate),
|
rate: this.getNumberMeta(transaction.rate),
|
||||||
cost: this.getNumberMeta(transaction.costLotAggregated.cost),
|
cost: this.getNumberMeta(transaction.costLotAggregated.cost),
|
||||||
|
value: this.getNumberMeta(value),
|
||||||
|
|
||||||
profitMargin: this.getNumberMeta(profitMargin),
|
profitMargin: this.getNumberMeta(profitMargin),
|
||||||
|
|
||||||
@@ -314,14 +319,12 @@ export default class InventoryDetails extends FinancialSheet {
|
|||||||
const value = sumBy(transactions, 'valueMovement.number');
|
const value = sumBy(transactions, 'valueMovement.number');
|
||||||
const quantity = sumBy(transactions, 'quantityMovement.number');
|
const quantity = sumBy(transactions, 'quantityMovement.number');
|
||||||
const profitMargin = sumBy(transactions, 'profitMargin.number');
|
const profitMargin = sumBy(transactions, 'profitMargin.number');
|
||||||
const cost = sumBy(transactions, 'cost.number');
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nodeType: INodeTypes.CLOSING_ENTRY,
|
nodeType: INodeTypes.CLOSING_ENTRY,
|
||||||
date: this.getDateMeta(this.query.toDate),
|
date: this.getDateMeta(this.query.toDate),
|
||||||
quantity: this.getTotalNumberMeta(quantity),
|
quantity: this.getTotalNumberMeta(quantity),
|
||||||
value: this.getTotalNumberMeta(value),
|
value: this.getTotalNumberMeta(value),
|
||||||
cost: this.getTotalNumberMeta(cost),
|
|
||||||
profitMargin: this.getTotalNumberMeta(profitMargin),
|
profitMargin: this.getTotalNumberMeta(profitMargin),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { Inject } from 'typedi';
|
import { Inject } from 'typedi';
|
||||||
import { raw } from 'objection';
|
import { raw } from 'objection';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { IItem, IInventoryDetailsQuery, IInventoryTransaction } from 'interfaces';
|
import {
|
||||||
|
IItem,
|
||||||
|
IInventoryDetailsQuery,
|
||||||
|
IInventoryTransaction,
|
||||||
|
} from 'interfaces';
|
||||||
import HasTenancyService from 'services/Tenancy/TenancyService';
|
import HasTenancyService from 'services/Tenancy/TenancyService';
|
||||||
|
|
||||||
export default class InventoryDetailsRepository {
|
export default class InventoryDetailsRepository {
|
||||||
@@ -47,6 +51,7 @@ export default class InventoryDetailsRepository {
|
|||||||
raw("IF(`DIRECTION` = 'OUT', `QUANTITY` * `RATE`, 0) as 'VALUE_OUT'")
|
raw("IF(`DIRECTION` = 'OUT', `QUANTITY` * `RATE`, 0) as 'VALUE_OUT'")
|
||||||
)
|
)
|
||||||
.modify('filterDateRange', null, openingBalanceDate)
|
.modify('filterDateRange', null, openingBalanceDate)
|
||||||
|
.orderBy('date', 'ASC')
|
||||||
.as('inventory_transactions');
|
.as('inventory_transactions');
|
||||||
|
|
||||||
const openingBalanceTransactions = await InventoryTransaction.query()
|
const openingBalanceTransactions = await InventoryTransaction.query()
|
||||||
@@ -79,6 +84,7 @@ export default class InventoryDetailsRepository {
|
|||||||
|
|
||||||
const inventoryTransactions = InventoryTransaction.query()
|
const inventoryTransactions = InventoryTransaction.query()
|
||||||
.modify('filterDateRange', filter.fromDate, filter.toDate)
|
.modify('filterDateRange', filter.fromDate, filter.toDate)
|
||||||
|
.orderBy('date', 'ASC')
|
||||||
.withGraphFetched('meta')
|
.withGraphFetched('meta')
|
||||||
.withGraphFetched('costLotAggregated');
|
.withGraphFetched('costLotAggregated');
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { Service, Inject } from 'typedi';
|
import { Service, Inject } from 'typedi';
|
||||||
import { raw } from 'objection';
|
import {
|
||||||
import { IInventoryDetailsQuery, IInventoryTransaction } from 'interfaces';
|
IInventoryDetailsQuery,
|
||||||
|
IInvetoryItemDetailDOO,
|
||||||
|
IInventoryItemDetailMeta,
|
||||||
|
} from 'interfaces';
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
import InventoryDetails from './InventoryDetails';
|
import InventoryDetails from './InventoryDetails';
|
||||||
import FinancialSheet from '../FinancialSheet';
|
import FinancialSheet from '../FinancialSheet';
|
||||||
import InventoryDetailsRepository from './InventoryDetailsRepository';
|
import InventoryDetailsRepository from './InventoryDetailsRepository';
|
||||||
|
import InventoryService from 'services/Inventory/Inventory';
|
||||||
|
import { parseBoolean } from 'utils';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class InventoryDetailsService extends FinancialSheet {
|
export default class InventoryDetailsService extends FinancialSheet {
|
||||||
@@ -15,11 +20,14 @@ export default class InventoryDetailsService extends FinancialSheet {
|
|||||||
@Inject()
|
@Inject()
|
||||||
reportRepo: InventoryDetailsRepository;
|
reportRepo: InventoryDetailsRepository;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
inventoryService: InventoryService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defaults balance sheet filter query.
|
* Defaults balance sheet filter query.
|
||||||
* @return {IBalanceSheetQuery}
|
* @return {IBalanceSheetQuery}
|
||||||
*/
|
*/
|
||||||
get defaultQuery(): IInventoryDetailsQuery {
|
private get defaultQuery(): IInventoryDetailsQuery {
|
||||||
return {
|
return {
|
||||||
fromDate: moment().startOf('year').format('YYYY-MM-DD'),
|
fromDate: moment().startOf('year').format('YYYY-MM-DD'),
|
||||||
toDate: moment().endOf('year').format('YYYY-MM-DD'),
|
toDate: moment().endOf('year').format('YYYY-MM-DD'),
|
||||||
@@ -34,15 +42,43 @@ export default class InventoryDetailsService extends FinancialSheet {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the balance sheet meta.
|
||||||
|
* @param {number} tenantId -
|
||||||
|
* @returns {IInventoryItemDetailMeta}
|
||||||
|
*/
|
||||||
|
private reportMetadata(tenantId: number): IInventoryItemDetailMeta {
|
||||||
|
const settings = this.tenancy.settings(tenantId);
|
||||||
|
|
||||||
|
const isCostComputeRunning =
|
||||||
|
this.inventoryService.isItemsCostComputeRunning(tenantId);
|
||||||
|
|
||||||
|
const organizationName = settings.get({
|
||||||
|
group: 'organization',
|
||||||
|
key: 'name',
|
||||||
|
});
|
||||||
|
const baseCurrency = settings.get({
|
||||||
|
group: 'organization',
|
||||||
|
key: 'base_currency',
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
isCostComputeRunning: parseBoolean(isCostComputeRunning, false),
|
||||||
|
organizationName,
|
||||||
|
baseCurrency,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the inventory details report data.
|
* Retrieve the inventory details report data.
|
||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
* @param {IInventoryDetailsQuery} query -
|
* @param {IInventoryDetailsQuery} query -
|
||||||
|
* @return {Promise<IInvetoryItemDetailDOO>}
|
||||||
*/
|
*/
|
||||||
public async inventoryDetails(
|
public async inventoryDetails(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
query: IInventoryDetailsQuery
|
query: IInventoryDetailsQuery
|
||||||
): Promise<any> {
|
): Promise<IInvetoryItemDetailDOO> {
|
||||||
// Settings tenant service.
|
// Settings tenant service.
|
||||||
const settings = this.tenancy.settings(tenantId);
|
const settings = this.tenancy.settings(tenantId);
|
||||||
const baseCurrency = settings.get({
|
const baseCurrency = settings.get({
|
||||||
@@ -76,6 +112,8 @@ export default class InventoryDetailsService extends FinancialSheet {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
data: inventoryDetailsInstance.reportData(),
|
data: inventoryDetailsInstance.reportData(),
|
||||||
|
query: filter,
|
||||||
|
meta: this.reportMetadata(tenantId),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' };
|
|||||||
|
|
||||||
export default class InventoryDetailsTable {
|
export default class InventoryDetailsTable {
|
||||||
/**
|
/**
|
||||||
* Constructor methiod.
|
* Constructor method.
|
||||||
* @param {ICashFlowStatement} reportStatement
|
* @param {ICashFlowStatement} reportStatement - Report statement.
|
||||||
*/
|
*/
|
||||||
constructor(reportStatement) {
|
constructor(reportStatement) {
|
||||||
this.report = reportStatement;
|
this.report = reportStatement;
|
||||||
@@ -59,8 +59,8 @@ export default class InventoryDetailsTable {
|
|||||||
accessor: 'quantityMovement.formattedNumber',
|
accessor: 'quantityMovement.formattedNumber',
|
||||||
},
|
},
|
||||||
{ key: 'rate', accessor: 'rate.formattedNumber' },
|
{ key: 'rate', accessor: 'rate.formattedNumber' },
|
||||||
{ key: 'value_movement', accessor: 'valueMovement.formattedNumber' },
|
{ key: 'total', accessor: 'total.formattedNumber' },
|
||||||
{ key: 'cost', accessor: 'cost.formattedNumber' },
|
{ key: 'value', accessor: 'valueMovement.formattedNumber' },
|
||||||
{ key: 'profit_margin', accessor: 'profitMargin.formattedNumber' },
|
{ key: 'profit_margin', accessor: 'profitMargin.formattedNumber' },
|
||||||
{ key: 'running_quantity', accessor: 'runningQuantity.formattedNumber' },
|
{ key: 'running_quantity', accessor: 'runningQuantity.formattedNumber' },
|
||||||
{ key: 'running_valuation', accessor: 'runningValuation.formattedNumber' },
|
{ key: 'running_valuation', accessor: 'runningValuation.formattedNumber' },
|
||||||
@@ -82,9 +82,9 @@ export default class InventoryDetailsTable {
|
|||||||
{ key: 'empty' },
|
{ key: 'empty' },
|
||||||
{ key: 'quantity', accessor: 'quantity.formattedNumber' },
|
{ key: 'quantity', accessor: 'quantity.formattedNumber' },
|
||||||
{ key: 'empty' },
|
{ key: 'empty' },
|
||||||
|
{ key: 'empty' },
|
||||||
{ key: 'value', accessor: 'value.formattedNumber' },
|
{ key: 'value', accessor: 'value.formattedNumber' },
|
||||||
];
|
];
|
||||||
|
|
||||||
return tableRowMapper(transaction, columns, {
|
return tableRowMapper(transaction, columns, {
|
||||||
rowTypes: [IROW_TYPE.OPENING_ENTRY],
|
rowTypes: [IROW_TYPE.OPENING_ENTRY],
|
||||||
});
|
});
|
||||||
@@ -102,8 +102,8 @@ export default class InventoryDetailsTable {
|
|||||||
{ key: 'empty' },
|
{ key: 'empty' },
|
||||||
{ key: 'quantity', accessor: 'quantity.formattedNumber' },
|
{ key: 'quantity', accessor: 'quantity.formattedNumber' },
|
||||||
{ key: 'empty' },
|
{ key: 'empty' },
|
||||||
|
{ key: 'empty' },
|
||||||
{ key: 'value', accessor: 'value.formattedNumber' },
|
{ key: 'value', accessor: 'value.formattedNumber' },
|
||||||
{ key: 'cost', accessor: 'cost.formattedNumber' },
|
|
||||||
{ key: 'profitMargin', accessor: 'profitMargin.formattedNumber' },
|
{ key: 'profitMargin', accessor: 'profitMargin.formattedNumber' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -171,13 +171,13 @@ export default class InventoryDetailsTable {
|
|||||||
{ key: 'date', label: 'Date' },
|
{ key: 'date', label: 'Date' },
|
||||||
{ key: 'transaction_type', label: 'Transaction type' },
|
{ key: 'transaction_type', label: 'Transaction type' },
|
||||||
{ key: 'transaction_id', label: 'Transaction #' },
|
{ key: 'transaction_id', label: 'Transaction #' },
|
||||||
{ key: 'quantity_movement', label: 'Quantity' },
|
{ key: 'quantity', label: 'Quantity' },
|
||||||
{ key: 'rate', label: 'Rate' },
|
{ key: 'rate', label: 'Rate' },
|
||||||
{ key: 'value_movement', label: 'Value' },
|
{ key: 'total', label: 'Total' },
|
||||||
{ key: 'cost', label: 'Cost' },
|
{ key: 'value', label: 'Value' },
|
||||||
{ key: 'profit_margin', label: 'Profit Margin' },
|
{ key: 'profit_margin', label: 'Profit Margin' },
|
||||||
{ key: 'quantity_on_hand', label: 'Running quantity' },
|
{ key: 'running_quantity', label: 'Running quantity' },
|
||||||
{ key: 'value', label: 'Running Value' },
|
{ key: 'running_value', label: 'Running Value' },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
ITransactionsByContactsFilter,
|
ITransactionsByContactsFilter,
|
||||||
IContact,
|
IContact,
|
||||||
ILedger,
|
ILedger,
|
||||||
|
ILedgerEntry,
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
import FinancialSheet from '../FinancialSheet';
|
import FinancialSheet from '../FinancialSheet';
|
||||||
|
|
||||||
@@ -20,20 +21,20 @@ export default class TransactionsByContact extends FinancialSheet {
|
|||||||
* @return {Omit<ITransactionsByContactsTransaction, 'runningBalance'>}
|
* @return {Omit<ITransactionsByContactsTransaction, 'runningBalance'>}
|
||||||
*/
|
*/
|
||||||
protected contactTransactionMapper(
|
protected contactTransactionMapper(
|
||||||
transaction
|
entry: ILedgerEntry,
|
||||||
): Omit<ITransactionsByContactsTransaction, 'runningBalance'> {
|
): Omit<ITransactionsByContactsTransaction, 'runningBalance'> {
|
||||||
const account = this.accountsGraph.getNodeData(transaction.accountId);
|
const account = this.accountsGraph.getNodeData(entry.accountId);
|
||||||
const currencyCode = 'USD';
|
const currencyCode = 'USD';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
credit: this.getContactAmount(transaction.credit, currencyCode),
|
credit: this.getContactAmount(entry.credit, currencyCode),
|
||||||
debit: this.getContactAmount(transaction.debit, currencyCode),
|
debit: this.getContactAmount(entry.debit, currencyCode),
|
||||||
accountName: account.name,
|
accountName: account.name,
|
||||||
currencyCode: 'USD',
|
currencyCode: 'USD',
|
||||||
transactionNumber: transaction.transactionNumber,
|
transactionNumber: entry.transactionNumber,
|
||||||
transactionType: transaction.transactionType,
|
transactionType: entry.referenceTypeFormatted,
|
||||||
date: transaction.date,
|
date: entry.date,
|
||||||
createdAt: transaction.createdAt,
|
createdAt: entry.createdAt,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user