Merge branch 'develop' into inconsistance-pagination-page-size

This commit is contained in:
Ahmed Bouhuolia
2024-08-14 22:01:04 +02:00
9 changed files with 169 additions and 14 deletions

View File

@@ -150,6 +150,15 @@
"contributions": [ "contributions": [
"bug" "bug"
] ]
},
{
"login": "Champetaman",
"name": "Camilo Oviedo",
"avatar_url": "https://avatars.githubusercontent.com/u/64604272?v=4",
"profile": "https://www.camilooviedo.com/",
"contributions": [
"code"
]
} }
], ],
"contributorsPerLine": 7, "contributorsPerLine": 7,

View File

@@ -129,6 +129,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<tr> <tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/oleynikd"><img src="https://avatars.githubusercontent.com/u/3976868?v=4?s=100" width="100px;" alt="Denis"/><br /><sub><b>Denis</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Aoleynikd" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/oleynikd"><img src="https://avatars.githubusercontent.com/u/3976868?v=4?s=100" width="100px;" alt="Denis"/><br /><sub><b>Denis</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Aoleynikd" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://myself.vercel.app/"><img src="https://avatars.githubusercontent.com/u/42431274?v=4?s=100" width="100px;" alt="Sachin Mittal"/><br /><sub><b>Sachin Mittal</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Amittalsam98" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://myself.vercel.app/"><img src="https://avatars.githubusercontent.com/u/42431274?v=4?s=100" width="100px;" alt="Sachin Mittal"/><br /><sub><b>Sachin Mittal</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Amittalsam98" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.camilooviedo.com/"><img src="https://avatars.githubusercontent.com/u/64604272?v=4?s=100" width="100px;" alt="Camilo Oviedo"/><br /><sub><b>Camilo Oviedo</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=Champetaman" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -67,7 +67,7 @@ export interface IPaymentReceivedEntry {
export interface IPaymentReceivedEntryDTO { export interface IPaymentReceivedEntryDTO {
id?: number; id?: number;
index: number; index: number;
paymentReceiveId: number; paymentReceiveId?: number;
invoiceId: number; invoiceId: number;
paymentAmount: number; paymentAmount: number;
} }

View File

@@ -1,18 +1,25 @@
import { Inject, Service } from 'typedi'; import { Inject, Service } from 'typedi';
import { initialize } from 'objection'; import { initialize } from 'objection';
import { Knex } from 'knex';
import { first } from 'lodash';
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
import { GetMatchedTransactionBillsTransformer } from './GetMatchedTransactionBillsTransformer'; import { GetMatchedTransactionBillsTransformer } from './GetMatchedTransactionBillsTransformer';
import { GetMatchedTransactionsFilter, MatchedTransactionPOJO } from './types'; import {
import HasTenancyService from '@/services/Tenancy/TenancyService'; GetMatchedTransactionsFilter,
IMatchTransactionDTO,
MatchedTransactionPOJO,
} from './types';
import { GetMatchedTransactionsByType } from './GetMatchedTransactionsByType'; import { GetMatchedTransactionsByType } from './GetMatchedTransactionsByType';
import { CreateBillPayment } from '@/services/Purchases/BillPayments/CreateBillPayment';
import { IBillPaymentDTO } from '@/interfaces';
@Service() @Service()
export class GetMatchedTransactionsByBills extends GetMatchedTransactionsByType { export class GetMatchedTransactionsByBills extends GetMatchedTransactionsByType {
@Inject() @Inject()
private tenancy: HasTenancyService; private transformer: TransformerInjectable;
@Inject() @Inject()
private transformer: TransformerInjectable; private createPaymentMadeService: CreateBillPayment;
/** /**
* Retrieves the matched transactions. * Retrieves the matched transactions.
@@ -71,4 +78,62 @@ export class GetMatchedTransactionsByBills extends GetMatchedTransactionsByType
new GetMatchedTransactionBillsTransformer() new GetMatchedTransactionBillsTransformer()
); );
} }
/**
* Creates the common matched transaction.
* @param {number} tenantId
* @param {Array<number>} uncategorizedTransactionIds
* @param {IMatchTransactionDTO} matchTransactionDTO
* @param {Knex.Transaction} trx
*/
public async createMatchedTransaction(
tenantId: number,
uncategorizedTransactionIds: Array<number>,
matchTransactionDTO: IMatchTransactionDTO,
trx?: Knex.Transaction
): Promise<void> {
await super.createMatchedTransaction(
tenantId,
uncategorizedTransactionIds,
matchTransactionDTO,
trx
);
const { Bill, UncategorizedCashflowTransaction, MatchedBankTransaction } =
this.tenancy.models(tenantId);
const uncategorizedTransactionId = first(uncategorizedTransactionIds);
const uncategorizedTransaction =
await UncategorizedCashflowTransaction.query(trx)
.findById(uncategorizedTransactionId)
.throwIfNotFound();
const bill = await Bill.query(trx)
.findById(matchTransactionDTO.referenceId)
.throwIfNotFound();
const createPaymentMadeDTO: IBillPaymentDTO = {
vendorId: bill.vendorId,
paymentAccountId: uncategorizedTransaction.accountId,
paymentDate: uncategorizedTransaction.date,
exchangeRate: 1,
entries: [
{
paymentAmount: bill.dueAmount,
billId: bill.id,
},
],
branchId: bill.branchId,
};
// Create a new bill payment associated to the matched bill.
const billPayment = await this.createPaymentMadeService.createBillPayment(
tenantId,
createPaymentMadeDTO,
trx
);
// Link the create bill payment with matched transaction.
await super.createMatchedTransaction(tenantId, uncategorizedTransactionIds, {
referenceType: 'BillPayment',
referenceId: billPayment.id,
}, trx);
}
} }

View File

@@ -1,22 +1,26 @@
import { Inject, Service } from 'typedi'; import { Inject, Service } from 'typedi';
import { initialize } from 'objection'; import { initialize } from 'objection';
import { Knex } from 'knex';
import { first } from 'lodash';
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
import { GetMatchedTransactionInvoicesTransformer } from './GetMatchedTransactionInvoicesTransformer'; import { GetMatchedTransactionInvoicesTransformer } from './GetMatchedTransactionInvoicesTransformer';
import { import {
GetMatchedTransactionsFilter, GetMatchedTransactionsFilter,
IMatchTransactionDTO,
MatchedTransactionPOJO, MatchedTransactionPOJO,
MatchedTransactionsPOJO, MatchedTransactionsPOJO,
} from './types'; } from './types';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { GetMatchedTransactionsByType } from './GetMatchedTransactionsByType'; import { GetMatchedTransactionsByType } from './GetMatchedTransactionsByType';
import { CreatePaymentReceived } from '@/services/Sales/PaymentReceived/CreatePaymentReceived';
import { IPaymentReceivedCreateDTO } from '@/interfaces';
@Service() @Service()
export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByType { export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByType {
@Inject() @Inject()
protected tenancy: HasTenancyService; protected transformer: TransformerInjectable;
@Inject() @Inject()
protected transformer: TransformerInjectable; protected createPaymentReceivedService: CreatePaymentReceived;
/** /**
* Retrieves the matched transactions. * Retrieves the matched transactions.
@@ -78,4 +82,64 @@ export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByTy
new GetMatchedTransactionInvoicesTransformer() new GetMatchedTransactionInvoicesTransformer()
); );
} }
/**
* Creates the common matched transaction.
* @param {number} tenantId
* @param {Array<number>} uncategorizedTransactionIds
* @param {IMatchTransactionDTO} matchTransactionDTO
* @param {Knex.Transaction} trx
*/
public async createMatchedTransaction(
tenantId: number,
uncategorizedTransactionIds: Array<number>,
matchTransactionDTO: IMatchTransactionDTO,
trx?: Knex.Transaction
) {
await super.createMatchedTransaction(
tenantId,
uncategorizedTransactionIds,
matchTransactionDTO,
trx
);
const { SaleInvoice, UncategorizedCashflowTransaction, MatchedBankTransaction } =
this.tenancy.models(tenantId);
const uncategorizedTransactionId = first(uncategorizedTransactionIds);
const uncategorizedTransaction =
await UncategorizedCashflowTransaction.query(trx)
.findById(uncategorizedTransactionId)
.throwIfNotFound();
const invoice = await SaleInvoice.query(trx)
.findById(matchTransactionDTO.referenceId)
.throwIfNotFound();
const createPaymentReceivedDTO: IPaymentReceivedCreateDTO = {
customerId: invoice.customerId,
paymentDate: uncategorizedTransaction.date,
amount: invoice.dueAmount,
depositAccountId: uncategorizedTransaction.accountId,
entries: [
{
index: 1,
invoiceId: invoice.id,
paymentAmount: invoice.dueAmount,
},
],
branchId: invoice.branchId,
};
// Create a payment received associated to the matched invoice.
const paymentReceived = await this.createPaymentReceivedService.createPaymentReceived(
tenantId,
createPaymentReceivedDTO,
{},
trx
);
// Link the create payment received with matched invoice transaction.
await super.createMatchedTransaction(tenantId, uncategorizedTransactionIds, {
referenceType: 'PaymentReceive',
referenceId: paymentReceived.id,
}, trx)
}
} }

View File

@@ -1,5 +1,3 @@
.root { .root {
padding: 20px; padding: 20px;
border: 2px dotted #c5cbd3; border: 2px dotted #c5cbd3;
@@ -9,4 +7,14 @@
flex-direction: column; flex-direction: column;
background: #fff; background: #fff;
position: relative; position: relative;
transition: background-color 0.3s ease, border-color 0.3s ease;
&.dropzoneAccept {
border-color: rgb(0, 82, 204);
background: rgba(0, 82, 204, 0.05);
}
&.dropzoneReject {
border-color: #AC2F33;
background: rgba(172, 47, 51, 0.05)
}
} }

View File

@@ -235,7 +235,14 @@ export const Dropzone = (_props: DropzoneProps) => {
> >
<Box <Box
{...getRootProps({ {...getRootProps({
className: clsx(styles.root, classNames?.root), className: clsx(
styles.root,
{
[styles.dropzoneAccept]: isDragAccept,
[styles.dropzoneReject]: isDragReject
},
classNames?.root
),
})} })}
// {...getStyles('root', { focusable: true })} // {...getStyles('root', { focusable: true })}
{...others} {...others}
@@ -253,7 +260,7 @@ export const Dropzone = (_props: DropzoneProps) => {
<input {...getInputProps(inputProps)} name={name} /> <input {...getInputProps(inputProps)} name={name} />
<div <div
data-enable-pointer-events={enablePointerEvents || undefined} data-enable-pointer-events={enablePointerEvents || undefined}
className={classNames?.content} className={clsx(styles.content, classNames?.content)}
> >
{children} {children}
</div> </div>
@@ -268,8 +275,6 @@ Dropzone.Idle = DropzoneIdle;
Dropzone.Reject = DropzoneReject; Dropzone.Reject = DropzoneReject;
type PossibleRef<T> = Ref<T> | undefined; type PossibleRef<T> = Ref<T> | undefined;
export function assignRef<T>(ref: PossibleRef<T>, value: T) { export function assignRef<T>(ref: PossibleRef<T>, value: T) {

View File

@@ -120,6 +120,7 @@ export function UploadAttachmentsPopoverContent({
uploadIcon={null} uploadIcon={null}
value={null} value={null}
title={''} title={''}
subtitle={'Drag and drop file here or choose file'}
classNames={{ root: styles.dropzoneRoot }} classNames={{ root: styles.dropzoneRoot }}
onChange={handleChangeDropzone} onChange={handleChangeDropzone}
dropzoneProps={{ dropzoneProps={{

View File

@@ -13,6 +13,8 @@ export function ImportDropzone() {
<Field id={'file'} name={'file'} type="file"> <Field id={'file'} name={'file'} type="file">
{({ form }) => ( {({ form }) => (
<ImportDropzoneField <ImportDropzoneField
title={'Drag and drop files here or click to select files'}
subtitle={''}
value={form.file} value={form.file}
onChange={(file) => { onChange={(file) => {
hideAlerts(); hideAlerts();