Skip to content

Commit

Permalink
Receipt: better support for host currency (#973)
Browse files Browse the repository at this point in the history
* enhancement(Receipt): better support for host currency

* test: Add codecov config

* enhancement(Receipt): more fixes on host currency
  • Loading branch information
Betree authored Dec 8, 2023
1 parent 26a3ad5 commit 346753a
Show file tree
Hide file tree
Showing 15 changed files with 2,021 additions and 13,438 deletions.
32 changes: 0 additions & 32 deletions .babelrc

This file was deleted.

32 changes: 32 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module.exports = {
presets: [
[
'next/babel',
{
'preset-env': {
modules: 'auto',
targets: { node: 'current' },
},
'transform-runtime': {
useESModules: false,
},
},
],
],
plugins: [
'lodash',
'babel-plugin-styled-components',
[
'formatjs',
{
idInterpolationPattern: '[sha512:contenthash:base64:6]',
ast: true,
},
],
],
env: {
development: {
compact: false,
},
},
};
2 changes: 2 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ignore:
- test
40 changes: 20 additions & 20 deletions components/Receipt.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@ export class Receipt extends React.Component {
number: PropTypes.string,
}),
}),
host: PropTypes.shape({
slug: PropTypes.string.isRequired,
website: PropTypes.string,
imageUrl: PropTypes.string,
}),
}).isRequired,
host: PropTypes.shape({
fromAccountHost: PropTypes.shape({
slug: PropTypes.string.isRequired,
website: PropTypes.string.isRequired,
imageUrl: PropTypes.string.isRequired,
}),
host: PropTypes.shape({
slug: PropTypes.string.isRequired,
website: PropTypes.string,
imageUrl: PropTypes.string,
}),
transactions: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
id: PropTypes.string.isRequired,
paymentMethod: PropTypes.object,
toAccount: PropTypes.shape({
type: PropTypes.string,
Expand Down Expand Up @@ -140,8 +140,8 @@ export class Receipt extends React.Component {
}

getBillTo() {
const { fromAccount } = this.props.receipt;
return fromAccount.host || fromAccount;
const { fromAccount, fromAccountHost } = this.props.receipt;
return fromAccountHost || fromAccount;
}

/** Generate a prettier reference for receipt by taking only the first part of the hash */
Expand Down Expand Up @@ -177,22 +177,22 @@ export class Receipt extends React.Component {
}

getTaxTotal() {
const getTaxAmountInHostCurrency = (t) => Math.abs(t.taxAmount.valueInCents) * (t.hostCurrencyFxRate || 1);
const getTaxAmountInHostCurrency = (t) => Math.abs(t.taxAmount?.valueInCents) * (t.hostCurrencyFxRate || 1);
return Math.round(sumBy(this.props.receipt.transactions, (t) => getTaxAmountInHostCurrency(t) || 0));
}

/** Returns the VAT number of the collective */
renderTaxIdNumbers() {
const { fromAccount, transactions } = this.props.receipt;
renderBillToTaxIdNumbers() {
const { fromAccount, fromAccountHost, transactions } = this.props.receipt;
const taxesSummary = getTaxIdNumbersFromTransactions(transactions);

// Expenses rely solely on the tax info stored in transactions. For orders, we look in the fromCollective
if (!transactions.every((t) => t.kind === 'EXPENSE')) {
const getVatNumberFromAccount = (a) => a?.settings?.VAT?.number;
if (getVatNumberFromAccount(fromAccount)) {
taxesSummary.push({ type: 'VAT', idNumber: getVatNumberFromAccount(fromAccount) });
} else if (getVatNumberFromAccount(fromAccount.host)) {
taxesSummary.push({ type: 'VAT', idNumber: getVatNumberFromAccount(fromAccount.host) });
} else if (getVatNumberFromAccount(fromAccountHost)) {
taxesSummary.push({ type: 'VAT', idNumber: getVatNumberFromAccount(fromAccountHost) });
}
}

Expand Down Expand Up @@ -262,12 +262,12 @@ export class Receipt extends React.Component {
{transactions.map((transaction) => {
const quantity = get(transaction, 'order.quantity') || 1;
const amountInHostCurrency = transaction.amountInHostCurrency.valueInCents;
const taxAmount = Math.abs(transaction.taxAmount.valueInCents || 0);
const taxAmount = Math.abs(transaction.taxAmount?.valueInCents || 0);
const hostCurrencyFxRate = transaction.hostCurrencyFxRate || 1;
const taxAmountInHostCurrency = taxAmount * hostCurrencyFxRate;
const grossPrice =
const grossPriceInHostCurrency =
amountInHostCurrency - (transaction.isRefund ? -taxAmountInHostCurrency : taxAmountInHostCurrency);
const unitGrossPrice = Math.abs(grossPrice / quantity);
const unitGrossPriceInHostCurrency = Math.abs(grossPriceInHostCurrency / quantity);
const transactionCurrency = transaction.hostCurrency || this.props.receipt.currency;
const isRefunded = !transaction.isRefund && transaction.refundTransaction;
return (
Expand Down Expand Up @@ -296,7 +296,7 @@ export class Receipt extends React.Component {
{quantity}
</Td>
<Td fontSize="11px" textAlign="center">
{formatCurrency(unitGrossPrice, transaction.currency)}
{formatCurrency(unitGrossPriceInHostCurrency, transactionCurrency)}
{transaction.amountInHostCurrency.currency !== transaction.amount.currency && (
<P fontSize="8px" color="black.600" mt={1}>
(
Expand Down Expand Up @@ -380,7 +380,7 @@ export class Receipt extends React.Component {
<AccountName account={billTo} />
</P>
<CollectiveAddress collective={billTo} />
{this.renderTaxIdNumbers()}
{this.renderBillToTaxIdNumbers()}
</Box>
</Box>
</Flex>
Expand Down Expand Up @@ -433,7 +433,7 @@ export class Receipt extends React.Component {
<EventDescription event={receipt.transactions[0].toAccount} />
</P>
)}
<Box width={1} css={{ flexGrow: 1 }}>
<Box id="invoice-content" width={1} css={{ flexGrow: 1 }}>
{this.renderTransactionsTable(transactionsChunk)}
{pageNumber === chunkedTransactions.length - 1 && (
<Flex justifyContent="flex-end" mt={3}>
Expand Down
8 changes: 8 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('jest').Config} */
module.exports = {
setupFilesAfterEnv: ['<rootDir>/test/setup.js'],
transformIgnorePatterns: ['/node_modules/(?!@opencollective/frontend-components)'],
moduleNameMapper: {
'\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)$': '<rootDir>/test/__mocks__/fileMock.js',
},
};
36 changes: 6 additions & 30 deletions lib/graphql/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ const receiptTransactionFragment = gql`
host {
...ReceiptTransactionHostFieldsFragment
}
oppositeTransaction {
host {
...ReceiptTransactionHostFieldsFragment
}
}
amount {
valueInCents
currency
Expand Down Expand Up @@ -65,16 +70,6 @@ const receiptTransactionFragment = gql`
address
country
}
... on AccountWithHost {
host {
...ReceiptTransactionHostFieldsFragment
}
}
... on Organization {
host {
...ReceiptTransactionHostFieldsFragment
}
}
}
toAccount {
id
Expand All @@ -88,16 +83,6 @@ const receiptTransactionFragment = gql`
address
country
}
... on AccountWithHost {
host {
...ReceiptTransactionHostFieldsFragment
}
}
... on Organization {
host {
...ReceiptTransactionHostFieldsFragment
}
}
... on Event {
startsAt
endsAt
Expand Down Expand Up @@ -163,16 +148,6 @@ export async function fetchInvoiceByDateRange(
address
country
}
... on AccountWithHost {
host {
...ReceiptTransactionHostFieldsFragment
}
}
... on Organization {
host {
...ReceiptTransactionHostFieldsFragment
}
}
}
transactions(
fromAccount: { slug: $fromCollectiveSlug }
Expand Down Expand Up @@ -319,6 +294,7 @@ export async function fetchExpenseInvoiceData(expenseId, accessToken, apiKey) {
host {
id
name
legalName
slug
type
expensePolicy
Expand Down
10 changes: 0 additions & 10 deletions lib/transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,3 @@ export const getTaxesBreakdown = (transactions) => {
),
}));
};

export const getHostFromTransaction = (transaction) => {
if (transaction.host) {
return transaction.host;
} else if (transaction.type === 'CREDIT') {
return transaction.fromAccount?.host;
} else {
return transaction.toAccount?.host;
}
};
Loading

1 comment on commit 346753a

@vercel
Copy link

@vercel vercel bot commented on 346753a Dec 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.