Compare commits

...

34 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
60f03f534b fix(subscription): event TS types 2024-08-24 21:51:15 +02:00
Ahmed Bouhuolia
8e94c7a755 feat(subscription): invalidate subscription cache 2024-08-24 21:40:28 +02:00
Ahmed Bouhuolia
3a2ca36c07 Merge branch 'develop' into listen-payment-webhooks 2024-08-24 21:08:47 +02:00
Ahmed Bouhuolia
88ece74c8a Merge pull request #622 from wolone/develop
Fix: Syntax error caused error
2024-08-24 20:48:14 +02:00
Ahmed Bouhuolia
67a8610328 feat: cancel/resume LS subscriptions 2024-08-24 20:46:30 +02:00
Ahmed Bouhuolia
278d61ce61 fix: Listen to payment webhooks 2024-08-24 18:50:12 +02:00
wolone
e72d6ad6b8 Fix: Syntax error caused error 2024-08-24 23:33:53 +08:00
Ahmed Bouhuolia
bf66b31679 Merge pull request #590 from bigcapitalhq/filter-uncategorized-bank-transactions
feat(banking): Filter uncategorized bank transactions by date
2024-08-23 17:42:59 +02:00
Ahmed Bouhuolia
b4d426d2e8 feat: Filter uncategorized transactions by date 2024-08-23 17:40:05 +02:00
Ahmed Bouhuolia
7f7dd270e7 Merge pull request #619 from bigcapitalhq/change-banking-service-language
feat: change banking service language
2024-08-23 02:00:47 +02:00
Ahmed Bouhuolia
f6bad8fe30 fix: wip filter uncategorized transactions by date 2024-08-23 01:57:52 +02:00
Ahmed Bouhuolia
820b363f79 feat: change banking service language 2024-08-22 20:49:15 +02:00
Ahmed Bouhuolia
07740a51ef Merge pull request #616 from bigcapitalhq/one-click-demo-account
feat(ee): One-click demo account
2024-08-22 20:33:06 +02:00
Ahmed Bouhuolia
d15fb6fe19 chore: document http query 2024-08-22 20:32:48 +02:00
Ahmed Bouhuolia
5749ccec81 feat: seed more demo bank transactions 2024-08-22 19:50:31 +02:00
Ahmed Bouhuolia
4a99f6c0cf feat: one-click demo account 2024-08-22 19:21:23 +02:00
Ahmed Bouhuolia
59f480f9d5 feat: add more demo account seeders 2024-08-22 13:04:51 +02:00
Ahmed Bouhuolia
6cb9c919b5 Merge branch 'develop' into one-click-demo-account 2024-08-22 10:48:24 +02:00
Ahmed Bouhuolia
1062b65b5b feat: wip bank account transactions date filter 2024-08-22 01:03:03 +02:00
Ahmed Bouhuolia
bf3a70cabd Merge branch 'develop' into filter-uncategorized-bank-transactions 2024-08-22 00:12:37 +02:00
Ahmed Bouhuolia
f46cd28f87 Merge pull request #618 from bigcapitalhq/display-details-bank-account
fix: Some bank account details hidden
2024-08-21 21:22:15 +02:00
Ahmed Bouhuolia
dffcfe50aa fix: some bank account details hidden 2024-08-21 21:19:59 +02:00
Ahmed Bouhuolia
fac55efbc7 Merge pull request #617 from bigcapitalhq/fix-impoort-itemns
fix: Cannot import items income and cost accounts
2024-08-21 19:33:50 +02:00
Ahmed Bouhuolia
8b90ce5f6c fix: cannot import items income and cost accounts 2024-08-21 19:32:59 +02:00
Ahmed Bouhuolia
705b8da053 fix: protect the one-click demo accounts endpoints 2024-08-21 01:04:18 +02:00
Ahmed Bouhuolia
4a05ccc692 feat: add more seedders 2024-08-20 23:40:23 +02:00
Ahmed Bouhuolia
3200d65d90 feat: add demo account button on onboarding 2024-08-20 22:01:36 +02:00
Ahmed Bouhuolia
3f23038227 chore: comment 2024-08-20 18:49:39 +02:00
Ahmed Bouhuolia
408c807fc2 feat: import sheet files on initializing demo account 2024-08-20 18:30:21 +02:00
Ahmed Bouhuolia
d29079a8c5 fix: one-click demo account 2024-08-20 12:51:23 +02:00
Ahmed Bouhuolia
cca596b4a9 fix: one click demo 2024-08-19 21:21:39 +02:00
Ahmed Bouhuolia
fed620505d feat: add one click endpoint 2024-08-19 12:10:38 +02:00
Ahmed Bouhuolia
a008aea3f3 feat(ee): one-click demo account 2024-08-19 12:08:58 +02:00
Ahmed Bouhuolia
df8b68fda6 feat(banking): Filter uncategorized bank transactions 2024-08-11 18:34:45 +02:00
115 changed files with 2425 additions and 183 deletions

View File

@@ -46,6 +46,10 @@ export class ExcludeBankTransactionsController extends BaseController {
query('account_id').optional().isNumeric().toInt(),
query('page').optional().isNumeric().toInt(),
query('page_size').optional().isNumeric().toInt(),
query('min_date').optional({ nullable: true }).isISO8601().toDate(),
query('max_date').optional({ nullable: true }).isISO8601().toDate(),
query('min_amount').optional({ nullable: true }).isFloat().toFloat(),
query('max_amount').optional({ nullable: true }).isFloat().toFloat(),
],
this.validationResult,
this.getExcludedBankTransactions.bind(this)

View File

@@ -21,6 +21,10 @@ export class RecognizedTransactionsController extends BaseController {
query('page').optional().isNumeric().toInt(),
query('page_size').optional().isNumeric().toInt(),
query('account_id').optional().isNumeric().toInt(),
query('min_date').optional({ nullable: true }).isISO8601().toDate(),
query('max_date').optional({ nullable: true }).isISO8601().toDate(),
query('min_amount').optional({ nullable: true }).isFloat().toFloat(),
query('max_amount').optional({ nullable: true }).isFloat().isFloat(),
],
this.validationResult,
this.getRecognizedTransactions.bind(this)

View File

@@ -84,6 +84,10 @@ export default class NewCashflowTransactionController extends BaseController {
param('id').exists().isNumeric().toInt(),
query('page').optional().isNumeric().toInt(),
query('page_size').optional().isNumeric().toInt(),
query('min_date').optional({ nullable: true }).isISO8601().toDate(),
query('max_date').optional({ nullable: true }).isISO8601().toDate(),
query('min_amount').optional({ nullable: true }).isFloat().toFloat(),
query('max_amount').optional({ nullable: true }).isFloat().toFloat(),
];
}

View File

@@ -0,0 +1,87 @@
import { Router, Request, Response, NextFunction } from 'express';
import { Service, Inject } from 'typedi';
import { body } from 'express-validator';
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
import BaseController from '@/api/controllers/BaseController';
import { OneClickDemoApplication } from '@/services/OneClickDemo/OneClickDemoApplication';
import config from '@/config';
@Service()
export class OneClickDemoController extends BaseController {
@Inject()
private oneClickDemoApp: OneClickDemoApplication;
/**
* Router constructor method.
*/
router() {
const router = Router();
// Protects the endpoints if the feature is not enabled.
const protectMiddleware = (
req: Request,
res: Response,
next: NextFunction
) => {
// Add your protection logic here
if (config.oneClickDemoAccounts) {
next();
} else {
res.status(403).send({ message: 'Forbidden' });
}
};
router.post(
'/one_click',
protectMiddleware,
asyncMiddleware(this.oneClickDemo.bind(this))
);
router.post(
'/one_click_signin',
[body('demo_id').exists()],
this.validationResult,
protectMiddleware,
asyncMiddleware(this.oneClickSignIn.bind(this))
);
return router;
}
/**
* One-click demo application.
* @param {Request} req -
* @param {Response} res -
* @param {NextFunction} next -
*/
private async oneClickDemo(req: Request, res: Response, next: NextFunction) {
try {
const data = await this.oneClickDemoApp.createOneClick();
return res.status(200).send({
data,
message: 'The one-click demo has been created successfully.',
});
} catch (error) {
next(error);
}
}
/**
* Sign-in to one-click demo account.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
private async oneClickSignIn(
req: Request,
res: Response,
next: NextFunction
) {
const { demoId } = this.matchedBodyData(req);
try {
const data = await this.oneClickDemoApp.autoSignIn(demoId);
return res.status(200).send(data);
} catch (error) {
next(error);
}
}
}

View File

@@ -113,7 +113,7 @@ export class SubscriptionController extends BaseController {
const { tenantId } = req;
try {
await this.subscriptionApp.cancelSubscription(tenantId, '455610');
await this.subscriptionApp.cancelSubscription(tenantId);
return res.status(200).send({
status: 200,

View File

@@ -35,7 +35,7 @@ export class Webhooks extends BaseController {
*/
public async lemonWebhooks(req: Request, res: Response, next: NextFunction) {
const data = req.body;
const signature = req.headers['x-signature'] ?? '';
const signature = req.headers['x-signature'] as string ?? '';
const rawBody = req.rawBody;
try {

View File

@@ -63,6 +63,7 @@ import { BankingController } from './controllers/Banking/BankingController';
import { Webhooks } from './controllers/Webhooks/Webhooks';
import { ExportController } from './controllers/Export/ExportController';
import { AttachmentsController } from './controllers/Attachments/AttachmentsController';
import { OneClickDemoController } from './controllers/OneClickDemo/OneClickDemoController';
export default () => {
const app = Router();
@@ -80,6 +81,7 @@ export default () => {
app.use('/jobs', Container.get(Jobs).router());
app.use('/account', Container.get(Account).router());
app.use('/webhooks', Container.get(Webhooks).router());
app.use('/demo', Container.get(OneClickDemoController).router())
// - Dashboard routes.
// ---------------------------

View File

@@ -1,11 +1,21 @@
import { Request, Response, NextFunction } from 'express';
import { Container } from 'typedi';
import { Request, Response, NextFunction } from 'express';
import SettingsStore from '@/services/Settings/SettingsStore';
export default async (req: Request, res: Response, next: NextFunction) => {
const { tenantId } = req.user;
const Logger = Container.get('logger');
const settings = await initializeTenantSettings(tenantId);
req.settings = settings;
res.on('finish', async () => {
await settings.save();
});
next();
}
export const initializeTenantSettings = async (tenantId: number) => {
const tenantContainer = Container.of(`tenant-${tenantId}`);
if (tenantContainer && !tenantContainer.has('settings')) {
@@ -18,10 +28,5 @@ export default async (req: Request, res: Response, next: NextFunction) => {
await settings.load();
req.settings = settings;
res.on('finish', async () => {
await settings.save();
});
next();
return settings;
}

View File

@@ -4,6 +4,7 @@ import { Request } from 'express';
import TenancyService from '@/services/Tenancy/TenancyService';
import TenantsManagerService from '@/services/Tenancy/TenantsManager';
import rtlDetect from 'rtl-detect';
import { Tenant } from '@/system/models';
export default (req: Request, tenant: ITenant) => {
const { id: tenantId, organizationId } = tenant;
@@ -16,7 +17,7 @@ export default (req: Request, tenant: ITenant) => {
const tenantContainer = tenantServices.tenantContainer(tenantId);
tenantContainer.set('i18n', injectI18nUtils(req));
tenantContainer.set('i18n', injectI18nUtils());
const knexInstance = tenantServices.knex(tenantId);
const models = tenantServices.models(tenantId);
@@ -33,14 +34,35 @@ export default (req: Request, tenant: ITenant) => {
};
export const injectI18nUtils = (req) => {
const locale = req.getLocale();
const globalI18n = Container.get('i18n');
const locale = globalI18n.getLocale();
const direction = rtlDetect.getLangDir(locale);
return {
locale,
__: req.__,
__: globalI18n.__,
direction,
isRtl: direction === 'rtl',
isLtr: direction === 'ltr',
};
};
export const initalizeTenantServices = async (tenantId: number) => {
const tenant = await Tenant.query()
.findById(tenantId)
.withGraphFetched('metadata');
const tenantServices = Container.get(TenancyService);
const tenantsManager = Container.get(TenantsManagerService);
// Initialize the knex instance.
tenantsManager.setupKnexInstance(tenant);
const tenantContainer = tenantServices.tenantContainer(tenantId);
tenantContainer.set('i18n', injectI18nUtils());
tenantServices.knex(tenantId);
tenantServices.models(tenantId);
tenantServices.repositories(tenantId);
tenantServices.cache(tenantId);
};

View File

@@ -245,4 +245,9 @@ module.exports = {
loops: {
apiKey: process.env.LOOPS_API_KEY,
},
oneClickDemoAccounts: parseBoolean(
process.env.ONE_CLICK_DEMO_ACCOUNTS,
false
),
};

View File

@@ -7,7 +7,6 @@ export interface IRegisterDTO {
lastName: string;
email: string;
password: string;
organizationName: string;
}
export interface ILoginDTO {

View File

@@ -167,11 +167,18 @@ export interface CategorizeTransactionAsExpenseDTO {
export interface IGetUncategorizedTransactionsQuery {
page?: number;
pageSize?: number;
minDate?: Date;
maxDate?: Date;
minAmount?: number;
maxAmount?: number;
}
export interface IGetRecognizedTransactionsQuery {
page?: number;
pageSize?: number;
accountId?: number;
}
minDate?: Date;
maxDate?: Date;
minAmount?: number;
maxAmount?: number;
}

View File

@@ -33,3 +33,7 @@ export interface IOrganizationBuildEventPayload {
buildDTO: IOrganizationBuildDTO;
systemUser: ISystemUser;
}
export interface IOrganizationBuiltEventPayload {
tenantId: number;
}

View File

@@ -0,0 +1,8 @@
export interface SubscriptionPayload {
lemonSqueezyId?: string;
}
export enum SubscriptionPaymentStatus {
Succeed = 'succeed',
Failed = 'failed',
}

View File

@@ -75,6 +75,7 @@ export * from './Times';
export * from './ProjectProfitabilitySummary';
export * from './TaxRate';
export * from './Plaid';
export * from './Subscription';
export interface I18nService {
__: (input: string) => string;

View File

@@ -164,6 +164,10 @@ export class Transformer {
return date ? moment(date).format(this.dateFormat) : '';
}
protected formatDateFromNow(date){
return date ? moment(date).fromNow(true) : '';
}
/**
*
* @param number

View File

@@ -116,6 +116,8 @@ import { DecrementUncategorizedTransactionOnCategorize } from '@/services/Cashfl
import { DisconnectPlaidItemOnAccountDeleted } from '@/services/Banking/BankAccounts/events/DisconnectPlaidItemOnAccountDeleted';
import { LoopsEventsSubscriber } from '@/services/Loops/LoopsEventsSubscriber';
import { DeleteUncategorizedTransactionsOnAccountDeleting } from '@/services/Banking/BankAccounts/events/DeleteUncategorizedTransactionsOnAccountDeleting';
import { SeedInitialDemoAccountDataOnOrgBuild } from '@/services/OneClickDemo/events/SeedInitialDemoAccountData';
import { TriggerInvalidateCacheOnSubscriptionChange } from '@/services/Subscription/events/TriggerInvalidateCacheOnSubscriptionChange';
export default () => {
return new EventPublisher();
@@ -246,8 +248,10 @@ export const susbcribers = () => {
DeleteCashflowTransactionOnUncategorize,
PreventDeleteTransactionOnDelete,
// Subscription
SubscribeFreeOnSignupCommunity,
SendVerfiyMailOnSignUp,
TriggerInvalidateCacheOnSubscriptionChange,
// Attachments
AttachmentsOnSaleInvoiceCreated,
@@ -281,6 +285,9 @@ export const susbcribers = () => {
DeleteUncategorizedTransactionsOnAccountDeleting,
// Loops
LoopsEventsSubscriber
LoopsEventsSubscriber,
// Demo Account
SeedInitialDemoAccountDataOnOrgBuild,
];
};

View File

@@ -2,6 +2,7 @@ import { I18n } from 'i18n';
export default () => new I18n({
locales: ['en', 'ar'],
defaultLocale: 'en',
register: global,
directory: global.__locales_dir,
updateFiles: false,

View File

@@ -257,25 +257,25 @@ export default {
name: 'item.field.sell_price',
fieldType: 'number',
},
cost_price: {
costPrice: {
name: 'item.field.cost_price',
fieldType: 'number',
},
costAccount: {
costAccountId: {
name: 'item.field.cost_account',
fieldType: 'relation',
relationModel: 'Account',
relationImportMatch: ['name', 'code'],
importHint: 'Matches the account name or code.',
},
sellAccount: {
sellAccountId: {
name: 'item.field.sell_account',
fieldType: 'relation',
relationModel: 'Account',
relationImportMatch: ['name', 'code'],
importHint: 'Matches the account name or code.',
},
inventoryAccount: {
inventoryAccountId: {
name: 'item.field.inventory_account',
fieldType: 'relation',
relationModel: 'Account',

View File

@@ -1,8 +1,8 @@
/* eslint-disable global-require */
import moment from 'moment';
import { Model, mixin } from 'objection';
import TenantModel from 'models/TenantModel';
import ModelSettings from './ModelSetting';
import Account from './Account';
import UncategorizedCashflowTransactionMeta from './UncategorizedCashflowTransaction.meta';
export default class UncategorizedCashflowTransaction extends mixin(
@@ -166,6 +166,28 @@ export default class UncategorizedCashflowTransaction extends mixin(
pending(query) {
query.where('pending', true);
},
minAmount(query, minAmount) {
query.where('amount', '>=', minAmount);
},
maxAmount(query, maxAmount) {
query.where('amount', '<=', maxAmount);
},
toDate(query, toDate) {
const dateFormat = 'YYYY-MM-DD';
const _toDate = moment(toDate).endOf('day').format(dateFormat);
query.where('date', '<=', _toDate);
},
fromDate(query, fromDate) {
const dateFormat = 'YYYY-MM-DD';
const _fromDate = moment(fromDate).startOf('day').format(dateFormat);
query.where('date', '>=', _fromDate);
},
};
}

View File

@@ -1,5 +1,6 @@
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { Inject, Service } from 'typedi';
import moment from 'moment';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { ExcludedBankTransactionsQuery } from './_types';
import { UncategorizedTransactionTransformer } from '@/services/Cashflow/UncategorizedTransactionTransformer';
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
@@ -39,6 +40,18 @@ export class GetExcludedBankTransactionsService {
if (_query.accountId) {
q.where('account_id', _query.accountId);
}
if (_query.minDate) {
q.modify('fromDate', _query.minDate);
}
if (_query.maxDate) {
q.modify('toDate', _query.maxDate);
}
if (_query.minAmount) {
q.modify('minAmount', _query.minAmount);
}
if (_query.maxAmount) {
q.modify('maxAmount', _query.maxAmount);
}
})
.pagination(_query.page - 1, _query.pageSize);

View File

@@ -4,6 +4,10 @@ export interface ExcludedBankTransactionsQuery {
page?: number;
pageSize?: number;
accountId?: number;
minDate?: Date;
maxDate?: Date;
minAmount?: number;
maxAmount?: number;
}
export interface IBankTransactionUnexcludingEventPayload {

View File

@@ -106,6 +106,9 @@ export class TriggerRecognizedTransactions {
const batch = importFile.paramsParsed.batch;
const payload = { tenantId, transactionsCriteria: { batch } };
// Cannot continue if the imported resource is not bank account transactions.
if (importFile.resource !== 'UncategorizedCashflowTransaction') return;
await this.agenda.now('recognize-uncategorized-transactions-job', payload);
}
}

View File

@@ -8,7 +8,12 @@ export class CashflowAccountTransformer extends Transformer {
* @returns {string[]}
*/
public includeAttributes = (): string[] => {
return ['formattedAmount'];
return [
'formattedAmount',
'lastFeedsUpdatedAt',
'lastFeedsUpdatedAtFormatted',
'lastFeedsUpdatedFromNow',
];
};
/**
@@ -29,7 +34,7 @@ export class CashflowAccountTransformer extends Transformer {
/**
* Retrieve formatted account amount.
* @param {IAccount} invoice
* @param {IAccount} invoice
* @returns {string}
*/
protected formattedAmount = (account: IAccount): string => {
@@ -37,4 +42,22 @@ export class CashflowAccountTransformer extends Transformer {
currencyCode: account.currencyCode,
});
};
/**
* Retrieves the last feeds update at formatted date.
* @param {IAccount} account
* @returns {string}
*/
protected lastFeedsUpdatedAtFormatted(account: IAccount): string {
return this.formatDate(account.lastFeedsUpdatedAt);
}
/**
* Retrieves the last feeds updated from now.
* @param {IAccount} account
* @returns {string}
*/
protected lastFeedsUpdatedFromNow(account: IAccount): string {
return this.formatDateFromNow(account.lastFeedsUpdatedAt);
}
}

View File

@@ -23,7 +23,7 @@ export class GetRecognizedTransactionsService {
) {
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
const _filter = {
const _query = {
page: 1,
pageSize: 20,
...filter,
@@ -41,11 +41,26 @@ export class GetRecognizedTransactionsService {
// Exclude the pending transactions.
q.modify('notPending');
if (_filter.accountId) {
q.where('accountId', _filter.accountId);
if (_query.accountId) {
q.where('accountId', _query.accountId);
}
if (_query.minDate) {
q.modify('fromDate', _query.minDate);
}
if (_query.maxDate) {
q.modify('toDate', _query.maxDate);
}
if (_query.minAmount) {
q.modify('minAmount', _query.minAmount);
}
if (_query.maxAmount) {
q.modify('maxAmount', _query.maxAmount);
}
if (_query.accountId) {
q.where('accountId', _query.accountId);
}
})
.pagination(_filter.page - 1, _filter.pageSize);
.pagination(_query.page - 1, _query.pageSize);
const data = await this.transformer.transform(
tenantId,

View File

@@ -62,6 +62,19 @@ export class GetUncategorizedTransactions {
q.whereNull('matchedBankTransactions.id');
q.orderBy('date', 'DESC');
if (_query.minDate) {
q.modify('fromDate', _query.minDate);
}
if (_query.maxDate) {
q.modify('toDate', _query.maxDate);
}
if (_query.minAmount) {
q.modify('minAmount', _query.minAmount);
}
if (_query.maxAmount) {
q.modify('maxAmount', _query.maxAmount);
}
})
.pagination(_query.page - 1, _query.pageSize);

View File

@@ -87,7 +87,7 @@ export class UncategorizedTransactionsImportable extends Importable {
}
/**
* Transformes the import params before storing them.
* Transforms the import params before storing them.
* @param {Record<string, any>} parmas
*/
public transformParams(parmas: Record<string, any>) {

View File

@@ -23,7 +23,7 @@ export class ImportFileMapping {
*/
public async mapping(
tenantId: number,
importId: number,
importId: string,
maps: ImportMappingAttr[]
): Promise<ImportFileMapPOJO> {
const importFile = await Import.query()

View File

@@ -19,7 +19,7 @@ export class ImportFilePreview {
*/
public async preview(
tenantId: number,
importId: number
importId: string
): Promise<ImportFilePreviewPOJO> {
const knex = this.tenancy.knex(tenantId);
const trx = await knex.transaction({ isolationLevel: 'read uncommitted' });

View File

@@ -37,7 +37,7 @@ export class ImportFileProcess {
*/
public async import(
tenantId: number,
importId: number,
importId: string,
trx?: Knex.Transaction
): Promise<ImportFilePreviewPOJO> {
const importFile = await Import.query()

View File

@@ -25,7 +25,7 @@ export class ImportFileProcessCommit {
*/
public async commit(
tenantId: number,
importId: number
importId: string
): Promise<ImportFilePreviewPOJO> {
const knex = this.tenancy.knex(tenantId);
const trx = await knex.transaction({ isolationLevel: 'read uncommitted' });

View File

@@ -55,7 +55,7 @@ export class ImportResourceApplication {
*/
public async mapping(
tenantId: number,
importId: number,
importId: string,
maps: ImportMappingAttr[]
) {
return this.importMappingService.mapping(tenantId, importId, maps);
@@ -67,7 +67,7 @@ export class ImportResourceApplication {
* @param {number} importId - Import id.
* @returns {Promise<ImportFilePreviewPOJO>}
*/
public async preview(tenantId: number, importId: number) {
public async preview(tenantId: number, importId: string) {
return this.ImportFilePreviewService.preview(tenantId, importId);
}
@@ -77,7 +77,7 @@ export class ImportResourceApplication {
* @param {number} importId
* @returns {Promise<ImportFilePreviewPOJO>}
*/
public async process(tenantId: number, importId: number) {
public async process(tenantId: number, importId: string) {
return this.importProcessCommit.commit(tenantId, importId);
}

View File

@@ -43,12 +43,22 @@ export class CreateItem {
itemDTO.sellAccountId
);
}
// Validate the income account id existance if the item is sellable.
this.validators.validateIncomeAccountExistance(
itemDTO.sellable,
itemDTO.sellAccountId
);
if (itemDTO.costAccountId) {
await this.validators.validateItemCostAccountExistance(
tenantId,
itemDTO.costAccountId
);
}
// Validate the cost account id existance if the item is purchasable.
this.validators.validateCostAccountExistance(
itemDTO.purchasable,
itemDTO.costAccountId
);
if (itemDTO.inventoryAccountId) {
await this.validators.validateItemInventoryAccountExistance(
tenantId,

View File

@@ -55,6 +55,11 @@ export class EditItem {
itemDTO.categoryId
);
}
// Validate the income account id existance if the item is sellable.
this.validators.validateIncomeAccountExistance(
itemDTO.sellable,
itemDTO.sellAccountId
);
// Validate the sell account existance on the storage.
if (itemDTO.sellAccountId) {
await this.validators.validateItemSellAccountExistance(
@@ -62,6 +67,11 @@ export class EditItem {
itemDTO.sellAccountId
);
}
// Validate the cost account id existance if the item is purchasable.
this.validators.validateCostAccountExistance(
itemDTO.purchasable,
itemDTO.costAccountId
);
// Validate the cost account existance on the storage.
if (itemDTO.costAccountId) {
await this.validators.validateItemCostAccountExistance(

View File

@@ -85,6 +85,42 @@ export class ItemsValidators {
}
}
/**
* Validates income account existance.
* @param {number|null} sellable - Detarmines if the item sellable.
* @param {number|null} incomeAccountId - Income account id.
* @throws {ServiceError(ERRORS.INCOME_ACCOUNT_REQUIRED_WITH_SELLABLE_ITEM)}
*/
public validateIncomeAccountExistance(
sellable?: boolean,
incomeAccountId?: number
) {
if (sellable && !incomeAccountId) {
throw new ServiceError(
ERRORS.INCOME_ACCOUNT_REQUIRED_WITH_SELLABLE_ITEM,
'Income account is require with sellable item.'
);
}
}
/**
* Validates the cost account existance.
* @param {boolean|null} purchasable - Detarmines if the item purchasble.
* @param {number|null} costAccountId - Cost account id.
* @throws {ServiceError(ERRORS.COST_ACCOUNT_REQUIRED_WITH_PURCHASABLE_ITEM)}
*/
public validateCostAccountExistance(
purchasable: boolean,
costAccountId?: number
) {
if (purchasable && !costAccountId) {
throw new ServiceError(
ERRORS.COST_ACCOUNT_REQUIRED_WITH_PURCHASABLE_ITEM,
'The cost account is required with purchasable item.'
);
}
}
/**
* Validate item inventory account existance and type.
* @param {number} tenantId

View File

@@ -5,6 +5,7 @@ import { ServiceError } from '@/exceptions';
import TenancyService from '@/services/Tenancy/TenancyService';
import { ItemEntry } from '@/models';
import { entriesAmountDiff } from 'utils';
import { Knex } from 'knex';
const ERRORS = {
ITEMS_NOT_FOUND: 'ITEMS_NOT_FOUND',
@@ -58,13 +59,14 @@ export default class ItemsEntriesService {
*/
public async filterInventoryEntries(
tenantId: number,
entries: IItemEntry[]
entries: IItemEntry[],
trx?: Knex.Transaction
): Promise<IItemEntry[]> {
const { Item } = this.tenancy.models(tenantId);
const entriesItemsIds = entries.map((e) => e.itemId);
// Retrieve entries inventory items.
const inventoryItems = await Item.query()
const inventoryItems = await Item.query(trx)
.whereIn('id', entriesItemsIds)
.where('type', 'inventory');

View File

@@ -26,6 +26,11 @@ export const ERRORS = {
PURCHASE_TAX_RATE_NOT_FOUND: 'PURCHASE_TAX_RATE_NOT_FOUND',
SELL_TAX_RATE_NOT_FOUND: 'SELL_TAX_RATE_NOT_FOUND',
INCOME_ACCOUNT_REQUIRED_WITH_SELLABLE_ITEM:
'INCOME_ACCOUNT_REQUIRED_WITH_SELLABLE_ITEM',
COST_ACCOUNT_REQUIRED_WITH_PURCHASABLE_ITEM:
'COST_ACCOUNT_REQUIRED_WITH_PURCHASABLE_ITEM',
};
export const DEFAULT_VIEW_COLUMNS = [];

View File

@@ -0,0 +1,74 @@
import { Inject, Service } from 'typedi';
import { faker } from '@faker-js/faker';
import uniqid from 'uniqid';
import AuthenticationApplication from '../Authentication/AuthApplication';
import OrganizationService from '../Organization/OrganizationService';
import { OneClickDemo } from '@/system/models/OneclickDemo';
import { SystemUser } from '@/system/models';
import { IAuthSignInPOJO } from '@/interfaces';
import { ICreateOneClickDemoPOJO } from './interfaces';
import events from '@/subscribers/events';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import { defaultDemoOrganizationDTO } from './_constants';
@Service()
export class CreateOneClickDemo {
@Inject()
private authApp: AuthenticationApplication;
@Inject()
private organizationService: OrganizationService;
@Inject()
private eventPublisher: EventPublisher;
/**
* Creates one-click demo account.
* @returns {Promise<ICreateOneClickDemoPOJO>}
*/
public async createOneClickDemo(): Promise<ICreateOneClickDemoPOJO> {
const firstName = faker.person.firstName();
const lastName = faker.person.lastName();
const email = faker.internet.email();
const password = '123123123';
const demoId = uniqid();
await this.authApp.signUp({ firstName, lastName, email, password });
const signedIn = await this.authApp.signIn(email, password);
const tenantId = signedIn.tenant.id;
const userId = signedIn.user.id;
// Creates a new one-click demo.
await OneClickDemo.query().insert({ key: demoId, tenantId, userId });
const buildJob = await this.organizationService.buildRunJob(
tenantId,
defaultDemoOrganizationDTO,
signedIn.user
);
return { email, demoId, signedIn, buildJob };
}
/**
* Sign-in automicatlly using the demo id one creating an account finish.
* @param {string} oneClickDemoId -
* @returns {Promise<IAuthSignInPOJO>}
*/
async autoSignIn(oneClickDemoId: string): Promise<IAuthSignInPOJO> {
const foundOneclickDemo = await OneClickDemo.query()
.findOne('key', oneClickDemoId)
.throwIfNotFound();
const userId = foundOneclickDemo.userId;
const user = await SystemUser.query().findById(userId);
const email = user.email;
const password = '123123123';
const signedIn = await this.authApp.signIn(email, password);
return signedIn;
}
}

View File

@@ -0,0 +1,17 @@
export class SeedDemoAbstract {
/**
* Retrieves the seeder file mapping.
* @returns {Array<>}
*/
get mapping() {
return [];
}
/**
* Retireves the seeder file import params.
* @returns {Record<string, any>}
*/
get importParams() {
return {};
}
}

View File

@@ -0,0 +1,35 @@
import { SeedDemoAbstract } from './SeedDemoAbstract';
export class SeedDemoBankTransactions extends SeedDemoAbstract {
get mapping() {
return [
{ from: 'Date', to: 'date' },
{ from: 'Payee', to: 'payee' },
{ from: 'Description', to: 'description' },
{ from: 'Reference No.', to: 'referenceNo' },
{ from: 'Amount', to: 'amount' },
];
}
/**
* Retrieves the seeder file name.
* @returns {string}
*/
get importFileName() {
return `bank-transactions.csv`;
}
/**
* Retrieve the resource name of the seeder.
* @returns {string}
*/
get resource() {
return 'UncategorizedCashflowTransaction';
}
get importParams() {
return {
accountId: 1001,
};
}
}

View File

@@ -0,0 +1,37 @@
import { SeedDemoAbstract } from './SeedDemoAbstract';
export class SeedDemoAccountCustomers extends SeedDemoAbstract {
/**
* Retrieves the seeder file mapping.
*/
get mapping() {
return [
{ from: 'Customer Type', to: 'customerType' },
{ from: 'First Name', to: 'firstName' },
{ from: 'Last Name', to: 'lastName' },
{ from: 'Display Name', to: 'displayName' },
{ from: 'Email', to: 'email' },
{ from: 'Work Phone Number', to: 'workPhone' },
{ from: 'Personal Phone Number', to: 'personalPhone' },
{ from: 'Company Name', to: 'companyName' },
{ from: 'Website', to: 'website' },
{ from: 'Active', to: 'active' },
];
}
/**
* Retrieves the seeder file name.
* @returns {string}
*/
get importFileName() {
return `customers.csv`;
}
/**
* Retrieve the resource name of the seeder.
* @returns {string}
*/
get resource() {
return 'Customer';
}
}

View File

@@ -0,0 +1,39 @@
import { SeedDemoAbstract } from './SeedDemoAbstract';
export class SeedDemoAccountExpenses extends SeedDemoAbstract {
/**
* Retrieves the seeder file mapping.
*/
get mapping() {
return [
{ from: 'Payment Account', to: 'paymentAccountId' },
{ from: 'Reference No.', to: 'referenceNo' },
{ from: 'Payment Date', to: 'paymentDate' },
{ from: 'Description', to: 'description' },
{ from: 'Publish', to: 'publish' },
{
from: 'Expense Account',
to: 'expenseAccountId',
group: 'categories',
},
{ from: 'Amount', to: 'amount', group: 'categories' },
{ from: 'Line Description', to: 'description', group: 'categories' },
];
}
/**
* Retrieves the seeder file name.
* @returns {string}
*/
get importFileName() {
return `Expenses.csv`;
}
/**
* Retrieve the resource name of the seeder.
* @returns {string}
*/
get resource() {
return 'Expense';
}
}

View File

@@ -0,0 +1,45 @@
import { SeedDemoAbstract } from './SeedDemoAbstract';
export class SeedDemoAccountItems extends SeedDemoAbstract {
/**
* Retrieves the seeder file mapping.
*/
get mapping() {
return [
{ from: 'Item Type', to: 'type' },
{ from: 'Item Name', to: 'name' },
{ from: 'Item Code', to: 'code' },
{ from: 'Sellable', to: 'sellable' },
{ from: 'Purchasable', to: 'purchasable' },
{ from: 'Sell Price', to: 'sellPrice' },
{ from: 'Cost Price', to: 'costPrice' },
{ from: 'Cost Account', to: 'costAccountId' },
{ from: 'Sell Account', to: 'sellAccountId' },
{ from: 'Inventory Account', to: 'inventoryAccountId' },
{ from: 'Sell Description', to: 'sellDescription' },
{
from: 'Purchase Description',
to: 'purchaseDescription',
},
{ from: 'Note', to: 'note' },
{ from: 'Category', to: 'category' },
{ from: 'Active', to: 'active' },
];
}
/**
* Retrieves the seeder file name.
* @returns {string}
*/
get importFileName() {
return `items.csv`;
}
/**
* Retrieve the resource name of the seeder.
* @returns {string}
*/
get resource() {
return 'Item';
}
}

View File

@@ -0,0 +1,36 @@
import { SeedDemoAbstract } from './SeedDemoAbstract';
export class SeedDemoAccountManualJournals extends SeedDemoAbstract {
/**
* Retrieves the seeder file mapping.
*/
get mapping() {
return [
{ from: 'Date', to: 'date' },
{ from: 'Journal No', to: 'journalNumber' },
{ from: 'Reference No.', to: 'reference' },
{ from: 'Description', to: 'description' },
{ from: 'Publish', to: 'publish' },
{ from: 'Credit', to: 'credit', group: 'entries' },
{ from: 'Debit', to: 'debit', group: 'entries' },
{ from: 'Account', to: 'accountId', group: 'entries' },
{ from: 'Note', to: 'note', group: 'entries' },
];
}
/**
* Retrieves the seeder file name.
* @returns {string}
*/
get importFileName() {
return `manual-journals.csv`;
}
/**
* Retrieve the resource name of the seeder.
* @returns {string}
*/
get resource() {
return 'ManualJournal';
}
}

View File

@@ -0,0 +1,37 @@
import { SeedDemoAbstract } from './SeedDemoAbstract';
export class SeedDemoSaleInvoices extends SeedDemoAbstract {
get mapping() {
return [
{ from: 'Invoice Date', to: 'invoiceDate' },
{ from: 'Due Date', to: 'dueDate' },
{ from: 'Reference No.', to: 'referenceNo' },
{ from: 'Invoice No.', to: 'invoiceNo' },
{ from: 'Customer', to: 'customerId' },
{ from: 'Exchange Rate', to: 'exchangeRate' },
{ from: 'Invoice Message', to: 'invoiceMessage' },
{ from: 'Terms & Conditions', to: 'termsConditions' },
{ from: 'Delivered', to: 'delivered' },
{ from: 'Item', to: 'itemId', group: 'entries' },
{ from: 'Rate', to: 'rate', group: 'entries' },
{ from: 'Quantity', to: 'quantity', group: 'entries' },
{ from: 'Description', to: 'description', group: 'entries' },
];
}
/**
* Retrieves the seeder file name.
* @returns {string}
*/
get importFileName() {
return `sale-invoices.csv`;
}
/**
* Retrieve the resource name of the seeder.
* @returns {string}
*/
get resource() {
return 'SaleInvoice';
}
}

View File

@@ -0,0 +1,36 @@
import { SeedDemoAbstract } from './SeedDemoAbstract';
export class SeedDemoAccountVendors extends SeedDemoAbstract {
/**
* Retrieves the seeder file mapping.
*/
get mapping() {
return [
{ from: 'First Name', to: 'firstName' },
{ from: 'Last Name', to: 'lastName' },
{ from: 'Display Name', to: 'displayName' },
{ from: 'Email', to: 'email' },
{ from: 'Work Phone Number', to: 'workPhone' },
{ from: 'Personal Phone Number', to: 'personalPhone' },
{ from: 'Company Name', to: 'companyName' },
{ from: 'Website', to: 'website' },
{ from: 'Active', to: 'active' },
];
}
/**
* Retrieves the seeder file name.
* @returns {string}
*/
get importFileName() {
return `vendors.csv`;
}
/**
* Retrieve the resource name of the seeder.
* @returns {string}
*/
get resource() {
return 'Vendor';
}
}

View File

@@ -0,0 +1,25 @@
import { Inject, Service } from 'typedi';
import { CreateOneClickDemo } from './CreateOneClickDemo';
@Service()
export class OneClickDemoApplication {
@Inject()
private createOneClickDemoService: CreateOneClickDemo;
/**
* Creates one-click demo account.
* @returns {Promise<ICreateOneClickDemoPOJO>}
*/
public createOneClick() {
return this.createOneClickDemoService.createOneClickDemo();
}
/**
* Auto-sign-in to created demo account.
* @param {string} demoId -
* @returns {Promise<IAuthSignInPOJO>}
*/
public autoSignIn(demoId: string) {
return this.createOneClickDemoService.autoSignIn(demoId);
}
}

View File

@@ -0,0 +1,12 @@
export const defaultDemoOrganizationDTO = {
name: 'BIGCAPITAL, INC',
baseCurrency: 'USD',
location: 'US',
language: 'en',
industry: 'Technology',
fiscalYear: 'march',
timezone: 'US/Central',
dateFormat: 'MM/DD/yyyy',
}

View File

@@ -0,0 +1,113 @@
import { Inject } from 'typedi';
import { promises as fs } from 'fs';
import path from 'path';
import uniqid from 'uniqid';
import { isEmpty } from 'lodash';
import events from '@/subscribers/events';
import { PromisePool } from '@supercharge/promise-pool';
import { IOrganizationBuiltEventPayload } from '@/interfaces';
import { SeedDemoAccountItems } from '../DemoSeeders/SeedDemoItems';
import { ImportResourceApplication } from '@/services/Import/ImportResourceApplication';
import { getImportsStoragePath } from '@/services/Import/_utils';
import { OneClickDemo } from '@/system/models/OneclickDemo';
import { SeedDemoAccountCustomers } from '../DemoSeeders/SeedDemoCustomers';
import { SeedDemoAccountVendors } from '../DemoSeeders/SeedDemoVendors';
import { SeedDemoAccountManualJournals } from '../DemoSeeders/SeedDemoManualJournals';
import { SeedDemoAccountExpenses } from '../DemoSeeders/SeedDemoExpenses';
import { SeedDemoBankTransactions } from '../DemoSeeders/SeedDemoBankTransactions';
import { SeedDemoSaleInvoices } from '../DemoSeeders/SeedDemoSaleInvoices';
export class SeedInitialDemoAccountDataOnOrgBuild {
@Inject()
private importApp: ImportResourceApplication;
/**
* Attaches events with handlers.
*/
public attach = (bus) => {
bus.subscribe(
events.organization.built,
this.seedInitialDemoAccountDataOnOrgBuild.bind(this)
);
};
/**
* Demo account seeder.
*/
get seedDemoAccountSeeders() {
return [
SeedDemoAccountItems,
SeedDemoBankTransactions,
SeedDemoAccountCustomers,
SeedDemoAccountVendors,
SeedDemoAccountManualJournals,
SeedDemoSaleInvoices,
SeedDemoAccountExpenses,
];
}
/**
* Initialize the seeder sheet file to the import storage first.
* @param {string} fileName -
* @returns {Promise<void>}
*/
async initiateSeederFile(fileName: string) {
const destFileName = uniqid();
const source = path.join(global.__views_dir, `/demo-sheets`, fileName);
const destination = path.join(getImportsStoragePath(), destFileName);
// Use the fs.promises.copyFile method to copy the file
await fs.copyFile(source, destination);
return destFileName;
}
/**
* Seeds initial demo account data on organization build
* @param {IOrganizationBuildEventPayload}
*/
async seedInitialDemoAccountDataOnOrgBuild({
tenantId,
}: IOrganizationBuiltEventPayload) {
const foundDemo = await OneClickDemo.query().findOne('tenantId', tenantId);
// Can't continue if the found demo is not exists.
// Means that account is not demo account.
if (!foundDemo) {
return null;
}
const results = await PromisePool.for(this.seedDemoAccountSeeders)
.withConcurrency(1)
.process(async (SeedDemoAccountSeeder) => {
const seederInstance = new SeedDemoAccountSeeder();
// Initialize the seeder sheet file before importing.
const importFileName = await this.initiateSeederFile(seederInstance.importFileName);
// Import the given seeder file.
const importedFile = await this.importApp.import(
tenantId,
seederInstance.resource,
importFileName,
seederInstance.importParams
);
// Mapping the columns with resource fields.
await this.importApp.mapping(
tenantId,
importedFile.import.importId,
seederInstance.mapping
);
await this.importApp.preview(tenantId, importedFile.import.importId);
// Commit the imported file.
await this.importApp.process(
tenantId,
importedFile.import.importId
);
});
if (!isEmpty(results.errors)) {
throw results.errors;
}
}
}

View File

@@ -0,0 +1,8 @@
import { IAuthSignInPOJO } from '@/interfaces';
export interface ICreateOneClickDemoPOJO {
email: string;
demoId: string;
signedIn: IAuthSignInPOJO;
buildJob: any;
}

View File

@@ -5,6 +5,7 @@ import { ServiceError } from '@/exceptions';
import {
IOrganizationBuildDTO,
IOrganizationBuildEventPayload,
IOrganizationBuiltEventPayload,
IOrganizationUpdateDTO,
ISystemUser,
ITenant,
@@ -17,6 +18,8 @@ import { Tenant } from '@/system/models';
import OrganizationBaseCurrencyLocking from './OrganizationBaseCurrencyLocking';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { ERRORS } from './constants';
import { initializeTenantSettings } from '@/api/middleware/SettingsMiddleware';
import { initalizeTenantServices } from '@/api/middleware/TenantDependencyInjection';
@Service()
export default class OrganizationService {
@@ -62,6 +65,10 @@ export default class OrganizationService {
// Migrated tenant.
const migratedTenant = await tenant.$query().withGraphFetched('metadata');
// Injects the given tenant IoC services.
await initalizeTenantServices(tenantId);
await initializeTenantSettings(tenantId);
// Creates a tenancy object from given tenant model.
const tenancyContext =
this.tenantsManager.getSeedMigrationContext(migratedTenant);
@@ -82,6 +89,11 @@ export default class OrganizationService {
//
await this.flagTenantDBBatch(tenantId);
// Triggers the organization built event.
await this.eventPublisher.emitAsync(events.organization.built, {
tenantId: tenant.id,
} as IOrganizationBuiltEventPayload)
}
/**

View File

@@ -44,7 +44,7 @@ export class SaleInvoiceGLEntries {
// Find or create the A/R account.
const ARAccount = await accountRepository.findOrCreateAccountReceivable(
saleInvoice.currencyCode
saleInvoice.currencyCode, {}, trx
);
// Find or create tax payable account.
const taxPayableAccount = await accountRepository.findOrCreateTaxPayable(

View File

@@ -32,7 +32,8 @@ export class InvoiceInventoryTransactions {
const inventoryEntries =
await this.itemsEntriesService.filterInventoryEntries(
tenantId,
saleInvoice.entries
saleInvoice.entries,
trx
);
const transaction = {
transactionId: saleInvoice.id,

View File

@@ -4,8 +4,8 @@ import { configureLemonSqueezy } from './utils';
import { PlanSubscription } from '@/system/models';
import { ServiceError } from '@/exceptions';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import { ERRORS, IOrganizationSubscriptionCancel } from './types';
import events from '@/subscribers/events';
import { ERRORS, IOrganizationSubscriptionCanceled } from './types';
@Service()
export class LemonCancelSubscription {
@@ -18,12 +18,15 @@ export class LemonCancelSubscription {
* @param {number} subscriptionId
* @returns {Promise<void>}
*/
public async cancelSubscription(tenantId: number) {
public async cancelSubscription(
tenantId: number,
subscriptionSlug: string = 'main'
) {
configureLemonSqueezy();
const subscription = await PlanSubscription.query().findOne({
tenantId,
slug: 'main',
slug: subscriptionSlug,
});
if (!subscription) {
throw new ServiceError(ERRORS.SUBSCRIPTION_ID_NOT_ASSOCIATED_TO_TENANT);
@@ -35,13 +38,10 @@ export class LemonCancelSubscription {
if (cancelledSub.error) {
throw new Error(cancelledSub.error.message);
}
await PlanSubscription.query().findById(subscriptionId).patch({
canceledAt: new Date(),
});
// Triggers `onSubscriptionCanceled` event.
// Triggers `onSubscriptionCancelled` event.
await this.eventPublisher.emitAsync(
events.subscription.onSubscriptionCanceled,
{ tenantId, subscriptionId } as IOrganizationSubscriptionCanceled
events.subscription.onSubscriptionCancel,
{ tenantId, subscriptionId } as IOrganizationSubscriptionCancel
);
}
}

View File

@@ -18,25 +18,30 @@ export class LemonChangeSubscriptionPlan {
* @param {number} newVariantId - New variant id.
* @returns {Promise<void>}
*/
public async changeSubscriptionPlan(tenantId: number, newVariantId: number) {
public async changeSubscriptionPlan(
tenantId: number,
newVariantId: number,
subscriptionSlug: string = 'main'
) {
configureLemonSqueezy();
const subscription = await PlanSubscription.query().findOne({
tenantId,
slug: 'main',
slug: subscriptionSlug,
});
const lemonSubscriptionId = subscription.lemonSubscriptionId;
// Send request to Lemon Squeezy to change the subscription.
const updatedSub = await updateSubscription(lemonSubscriptionId, {
variantId: newVariantId,
invoiceImmediately: true,
});
if (updatedSub.error) {
throw new ServiceError('SOMETHING_WENT_WRONG');
}
// Triggers `onSubscriptionPlanChanged` event.
await this.eventPublisher.emitAsync(
events.subscription.onSubscriptionPlanChanged,
events.subscription.onSubscriptionPlanChange,
{
tenantId,
lemonSubscriptionId,

View File

@@ -1,11 +1,11 @@
import { Inject, Service } from 'typedi';
import { updateSubscription } from '@lemonsqueezy/lemonsqueezy.js';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import events from '@/subscribers/events';
import { configureLemonSqueezy } from './utils';
import { PlanSubscription } from '@/system/models';
import { ServiceError } from '@/exceptions';
import { ERRORS, IOrganizationSubscriptionResumed } from './types';
import { updateSubscription } from '@lemonsqueezy/lemonsqueezy.js';
import { ERRORS, IOrganizationSubscriptionResume } from './types';
@Service()
export class LemonResumeSubscription {
@@ -14,15 +14,16 @@ export class LemonResumeSubscription {
/**
* Resumes the main subscription of the given tenant.
* @param {number} tenantId -
* @param {number} tenantId - Tenant id.
* @param {string} subscriptionSlug - Subscription slug by default main subscription.
* @returns {Promise<void>}
*/
public async resumeSubscription(tenantId: number) {
public async resumeSubscription(tenantId: number, subscriptionSlug: string = 'main') {
configureLemonSqueezy();
const subscription = await PlanSubscription.query().findOne({
tenantId,
slug: 'main',
slug: subscriptionSlug,
});
if (!subscription) {
throw new ServiceError(ERRORS.SUBSCRIPTION_ID_NOT_ASSOCIATED_TO_TENANT);
@@ -33,16 +34,12 @@ export class LemonResumeSubscription {
cancelled: false,
});
if (returnedSub.error) {
throw new ServiceError('');
throw new ServiceError(ٌٌُERRORS.SOMETHING_WENT_WRONG_WITH_LS);
}
// Update the subscription of the organization.
await PlanSubscription.query().findById(subscriptionId).patch({
canceledAt: null,
});
// Triggers `onSubscriptionCanceled` event.
// Triggers `onSubscriptionResume` event.
await this.eventPublisher.emitAsync(
events.subscription.onSubscriptionResumed,
{ tenantId, subscriptionId } as IOrganizationSubscriptionResumed
events.subscription.onSubscriptionResume,
{ tenantId, subscriptionId } as IOrganizationSubscriptionResume
);
}
}

View File

@@ -59,11 +59,25 @@ export class LemonSqueezyWebhooks {
const userId = eventBody.meta.custom_data?.user_id;
const tenantId = eventBody.meta.custom_data?.tenant_id;
const subscriptionSlug = 'main';
if (!webhookHasMeta(eventBody)) {
throw new Error("Event body is missing the 'meta' property.");
} else if (webhookHasData(eventBody)) {
if (webhookEvent.startsWith('subscription_payment_')) {
// Marks the main subscription payment as succeed.
if (webhookEvent === 'subscription_payment_success') {
await this.subscriptionService.markSubscriptionPaymentSucceed(
tenantId,
subscriptionSlug
);
// Marks the main subscription payment as failed.
} else if (webhookEvent === 'subscription_payment_failed') {
await this.subscriptionService.markSubscriptionPaymentFailed(
tenantId,
subscriptionSlug
);
}
// Save subscription invoices; eventBody is a SubscriptionInvoice
// Not implemented.
} else if (webhookEvent.startsWith('subscription_')) {
@@ -74,16 +88,39 @@ export class LemonSqueezyWebhooks {
// We assume that the Plan table is up to date.
const plan = await Plan.query().findOne('lemonVariantId', variantId);
// Update the subscription in the database.
const priceId = attributes.first_subscription_item.price_id;
const subscriptionId = eventBody.data.id;
// Throw error early if the given lemon variant id is not associated to any plan.
if (!plan) {
throw new Error(`Plan with variantId ${variantId} not found.`);
} else {
// Update the subscription in the database.
const priceId = attributes.first_subscription_item.price_id;
// Create a new subscription of the tenant.
if (webhookEvent === 'subscription_created') {
await this.subscriptionService.newSubscribtion(tenantId, plan.slug);
}
}
// Create a new subscription of the tenant.
if (webhookEvent === 'subscription_created') {
await this.subscriptionService.newSubscribtion(
tenantId,
plan.slug,
subscriptionSlug,
{ lemonSqueezyId: subscriptionId }
);
// Cancel the given subscription of the organization.
} else if (webhookEvent === 'subscription_cancelled') {
await this.subscriptionService.cancelSubscription(
tenantId,
subscriptionSlug
);
} else if (webhookEvent === 'subscription_plan_changed') {
await this.subscriptionService.subscriptionPlanChanged(
tenantId,
plan.slug,
subscriptionSlug
);
} else if (webhookEvent === 'subscription_resumed') {
await this.subscriptionService.resumeSubscription(
tenantId,
subscriptionSlug
);
}
} else if (webhookEvent.startsWith('order_')) {
// Save orders; eventBody is a "Order"

View File

@@ -1,22 +1,29 @@
import { Service } from 'typedi';
import { NotAllowedChangeSubscriptionPlan } from '@/exceptions';
import { Plan, Tenant } from '@/system/models';
import { Inject, Service } from 'typedi';
import { NotAllowedChangeSubscriptionPlan, ServiceError } from '@/exceptions';
import { Plan, PlanSubscription, Tenant } from '@/system/models';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import events from '@/subscribers/events';
import { SubscriptionPayload, SubscriptionPaymentStatus } from '@/interfaces';
import { ERRORS } from './types';
@Service()
export class Subscription {
@Inject()
private eventPublisher: EventPublisher;
/**
* Give the tenant a new subscription.
* @param {number} tenantId - Tenant id.
* @param {string} planSlug - Plan slug.
* @param {string} invoiceInterval
* @param {number} invoicePeriod
* @param {string} subscriptionSlug
* @param {string} planSlug - Plan slug of the new subscription.
* @param {string} subscriptionSlug - Subscription slug by default takes main subscription
* @param {SubscriptionPayload} payload - Subscription payload.
*/
public async newSubscribtion(
tenantId: number,
planSlug: string,
subscriptionSlug: string = 'main'
) {
subscriptionSlug: string = 'main',
payload?: SubscriptionPayload
): Promise<void> {
const tenant = await Tenant.query().findById(tenantId).throwIfNotFound();
const plan = await Plan.query().findOne('slug', planSlug).throwIfNotFound();
@@ -45,8 +52,169 @@ export class Subscription {
plan.id,
invoiceInterval,
invoicePeriod,
subscriptionSlug
subscriptionSlug,
payload
);
}
}
/**
* Cancels the given tenant subscription.
* @param {number} tenantId - Tenant id.
* @param {string} subscriptionSlug - Subscription slug.
*/
async cancelSubscription(
tenantId: number,
subscriptionSlug: string = 'main'
): Promise<void> {
const tenant = await Tenant.query().findById(tenantId).throwIfNotFound();
const subscription = await PlanSubscription.query().findOne({
tenantId,
slug: subscriptionSlug,
});
// Throw error early if the subscription is not exist.
if (!subscription) {
throw new ServiceError(ERRORS.SUBSCRIPTION_NOT_EXIST);
}
// Throw error early if the subscription is already canceled.
if (subscription.canceled()) {
throw new ServiceError(ERRORS.SUBSCRIPTION_ALREADY_CANCELED);
}
await subscription.$query().patch({ canceledAt: new Date() });
// Triggers `onSubscriptionCancelled` event.
await this.eventPublisher.emitAsync(
events.subscription.onSubscriptionCancelled,
{
tenantId,
subscriptionSlug,
}
);
}
/**
* Resumes the given tenant subscription.
* @param {number} tenantId
* @param {string} subscriptionSlug - Subscription slug by deafult main subscription.
* @returns {Promise<void>}
*/
async resumeSubscription(
tenantId: number,
subscriptionSlug: string = 'main'
) {
const tenant = await Tenant.query().findById(tenantId).throwIfNotFound();
const subscription = await PlanSubscription.query().findOne({
tenantId,
slug: subscriptionSlug,
});
// Throw error early if the subscription is not exist.
if (!subscription) {
throw new ServiceError(ERRORS.SUBSCRIPTION_NOT_EXIST);
}
// Throw error early if the subscription is not cancelled.
if (!subscription.canceled()) {
throw new ServiceError(ERRORS.SUBSCRIPTION_ALREADY_ACTIVE);
}
await subscription.$query().patch({ canceledAt: null });
// Triggers `onSubscriptionResumed` event.
await this.eventPublisher.emitAsync(
events.subscription.onSubscriptionResumed,
{ tenantId, subscriptionSlug }
);
}
/**
* Mark the given subscription payment of the tenant as succeed.
* @param {number} tenantId
* @param {string} newPlanSlug
* @param {string} subscriptionSlug
*/
async subscriptionPlanChanged(
tenantId: number,
newPlanSlug: string,
subscriptionSlug: string = 'main'
): Promise<void> {
const tenant = await Tenant.query().findById(tenantId).throwIfNotFound();
const newPlan = await Plan.query()
.findOne('slug', newPlanSlug)
.throwIfNotFound();
const subscription = await PlanSubscription.query().findOne({
tenantId,
slug: subscriptionSlug,
});
if (subscription.planId === newPlan.id) {
throw new ServiceError('');
}
await subscription.$query().patch({ planId: newPlan.id });
// Triggers `onSubscriptionPlanChanged` event.
await this.eventPublisher.emitAsync(
events.subscription.onSubscriptionPlanChanged,
{
tenantId,
newPlanSlug,
subscriptionSlug,
}
);
}
/**
* Marks the subscription payment as succeed.
* @param {number} tenantId - Tenant id.
* @param {string} subscriptionSlug - Given subscription slug by default main subscription.
* @returns {Promise<void>}
*/
async markSubscriptionPaymentSucceed(
tenantId: number,
subscriptionSlug: string = 'main'
): Promise<void> {
const subscription = await PlanSubscription.query()
.findOne({ tenantId, slug: subscriptionSlug })
.throwIfNotFound();
await subscription
.$query()
.patch({ paymentStatus: SubscriptionPaymentStatus.Succeed });
// Triggers `onSubscriptionSucceed` event.
await this.eventPublisher.emitAsync(
events.subscription.onSubscriptionPaymentSucceed,
{
tenantId,
subscriptionSlug,
}
);
}
/**
* Marks the given subscription payment of the tenant as failed.
* @param {number} tenantId - Tenant id.
* @param {string} subscriptionSlug - Given subscription slug.
* @returns {Prmise<void>}
*/
async markSubscriptionPaymentFailed(
tenantId: number,
subscriptionSlug: string = 'main'
): Promise<void> {
const subscription = await PlanSubscription.query()
.findOne({ tenantId, slug: subscriptionSlug })
.throwIfNotFound();
await subscription
.$query()
.patch({ paymentStatus: SubscriptionPaymentStatus.Failed });
// Triggers `onSubscriptionPaymentFailed` event.
await this.eventPublisher.emitAsync(
events.subscription.onSubscriptionPaymentFailed,
{
tenantId,
subscriptionSlug,
}
);
}
}

View File

@@ -20,8 +20,14 @@ export class SubscriptionApplication {
* @param {string} id
* @returns {Promise<void>}
*/
public cancelSubscription(tenantId: number, id: string) {
return this.cancelSubscriptionService.cancelSubscription(tenantId, id);
public cancelSubscription(
tenantId: number,
subscriptionSlug: string = 'main'
) {
return this.cancelSubscriptionService.cancelSubscription(
tenantId,
subscriptionSlug
);
}
/**
@@ -29,8 +35,14 @@ export class SubscriptionApplication {
* @param {number} tenantId
* @returns {Promise<void>}
*/
public resumeSubscription(tenantId: number) {
return this.resumeSubscriptionService.resumeSubscription(tenantId);
public resumeSubscription(
tenantId: number,
subscriptionSlug: string = 'main'
) {
return this.resumeSubscriptionService.resumeSubscription(
tenantId,
subscriptionSlug
);
}
/**

View File

@@ -1,8 +1,8 @@
import { Inject, Service } from 'typedi';
import { IAuthSignedUpEventPayload } from '@/interfaces';
import events from '@/subscribers/events';
import config from '@/config';
import { Subscription } from '../Subscription';
import { Inject, Service } from 'typedi';
@Service()
export class SubscribeFreeOnSignupCommunity {

View File

@@ -0,0 +1,29 @@
import events from '@/subscribers/events';
import Container from 'typedi';
export class TriggerInvalidateCacheOnSubscriptionChange {
/**
* Attaches events with handlers.
*/
public attach = (bus) => {
bus.subscribe(
events.subscription.onSubscriptionCancelled,
this.triggerInvalidateCache.bind(this)
);
bus.subscribe(
events.subscription.onSubscriptionResumed,
this.triggerInvalidateCache.bind(this)
);
bus.subscribe(
events.subscription.onSubscriptionPlanChanged,
this.triggerInvalidateCache.bind(this)
);
};
private triggerInvalidateCache() {
const io = Container.get('socket');
// Notify the frontend to reflect the new transactions changes.
io.emit('SUBSCRIPTION_CHANGED', { subscriptionSlug: 'main' });
}
}

View File

@@ -1,6 +1,10 @@
export const ERRORS = {
SUBSCRIPTION_ID_NOT_ASSOCIATED_TO_TENANT:
'SUBSCRIPTION_ID_NOT_ASSOCIATED_TO_TENANT',
SUBSCRIPTION_NOT_EXIST: 'SUBSCRIPTION_NOT_EXIST',
SUBSCRIPTION_ALREADY_CANCELED: 'SUBSCRIPTION_ALREADY_CANCELED',
SUBSCRIPTION_ALREADY_ACTIVE: 'SUBSCRIPTION_ALREADY_ACTIVE',
SOMETHING_WENT_WRONG_WITH_LS: 'SOMETHING_WENT_WRONG_WITH_LS',
};
export interface IOrganizationSubscriptionChanged {
@@ -9,11 +13,20 @@ export interface IOrganizationSubscriptionChanged {
newVariantId: number;
}
export interface IOrganizationSubscriptionCanceled {
export interface IOrganizationSubscriptionCancel {
tenantId: number;
subscriptionId: string;
}
export interface IOrganizationSubscriptionCancelled {
tenantId: number;
subscriptionId: string;
}
export interface IOrganizationSubscriptionResume {
tenantId: number;
subscriptionId: number;
}
export interface IOrganizationSubscriptionResumed {
tenantId: number;
subscriptionId: number;

View File

@@ -35,6 +35,8 @@ export default {
*/
organization: {
build: 'onOrganizationBuild',
built: 'onOrganizationBuilt',
seeded: 'onOrganizationSeeded',
baseCurrencyUpdated: 'onOrganizationBaseCurrencyUpdated',
@@ -44,10 +46,19 @@ export default {
* Organization subscription.
*/
subscription: {
onSubscriptionCanceled: 'onSubscriptionCanceled',
onSubscriptionCancel: 'onSubscriptionCancel',
onSubscriptionCancelled: 'onSubscriptionCancelled',
onSubscriptionResume: 'onSubscriptionResume',
onSubscriptionResumed: 'onSubscriptionResumed',
onSubscriptionPlanChange: 'onSubscriptionPlanChange',
onSubscriptionPlanChanged: 'onSubscriptionPlanChanged',
onSubscribed: 'onOrganizationSubscribed',
onSubscriptionSubscribed: 'onSubscriptionSubscribed',
onSubscriptionPaymentSucceed: 'onSubscriptionPaymentSucceed',
onSubscriptionPaymentFailed: 'onSubscriptionPaymentFailed'
},
/**

View File

@@ -0,0 +1,21 @@
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = function (knex) {
return knex.schema.createTable('oneclick_demos', (table) => {
table.increments('id');
table.string('key');
table.integer('tenant_id').unsigned();
table.integer('user_id').unsigned();
table.timestamps();
});
};
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function (knex) {
return knex.schema.dropTableIfExists('oneclick_demos');
};

View File

@@ -0,0 +1,19 @@
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = function (knex) {
return knex.schema.table('subscription_plan_subscriptions', (table) => {
table.string('payment_status');
});
};
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function (knex) {
return knex.schema.table('subscription_plan_subscriptions', (table) => {
table.dropColumn('payment_status');
});
};

View File

@@ -0,0 +1,17 @@
import SystemModel from '@/system/models/SystemModel';
export class OneClickDemo extends SystemModel {
/**
* Table name
*/
static get tableName() {
return 'oneclick_demos';
}
/**
* Timestamps columns.
*/
get timestamps() {
return ['createdAt'];
}
}

View File

@@ -3,6 +3,10 @@ import SystemModel from '@/system/models/SystemModel';
import { PlanSubscription } from '..';
export default class Plan extends mixin(SystemModel) {
price: number;
invoiceInternal: number;
invoicePeriod: string;
/**
* Table name.
*/

View File

@@ -198,14 +198,16 @@ export default class Tenant extends BaseModel {
planId,
invoiceInterval,
invoicePeriod,
subscriptionSlug
subscriptionSlug,
payload?,
) {
return Tenant.newSubscription(
this.id,
planId,
invoiceInterval,
invoicePeriod,
subscriptionSlug
subscriptionSlug,
payload
);
}
@@ -217,7 +219,8 @@ export default class Tenant extends BaseModel {
planId: number,
invoiceInterval: 'month' | 'year',
invoicePeriod: number,
subscriptionSlug: string
subscriptionSlug: string,
payload?: { lemonSqueezyId: string }
) {
const period = new SubscriptionPeriod(invoiceInterval, invoicePeriod);
@@ -227,6 +230,7 @@ export default class Tenant extends BaseModel {
planId,
startsAt: period.getStartDate(),
endsAt: period.getEndDate(),
lemonSubscriptionId: payload?.lemonSqueezyId || null,
});
}
}

BIN
packages/server/views/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,23 @@
Payment Date,Reference No.,Payment Account,Description,Currency Code,Exchange Rate,Expense Account,Amount,Line Description,Publish
2024-03-01,REF-1,Petty Cash,Vel et dolorem architecto veniam.,,,Office expenses,9000,Voluptates voluptas corporis vel.,T
2024-03-02,REF-2,Petty Cash,Id est molestias.,,,Office expenses,9000,Eos voluptatem cumque et voluptate reiciendis.,T
2024-03-03,REF-3,Petty Cash,Quam cupiditate at nihil dicta dignissimos non fugit illo.,,,Office expenses,9000,Hic alias rerum sed commodi dolores sint animi perferendis.,T
2024-03-04,REF-4,Petty Cash,Et voluptatem consequatur corrupti beatae sit.,,,Office expenses,9000,Exercitationem impedit praesentium et eaque.,T
2024-03-05,REF-5,Petty Cash,Illo aut ad id et non error et reiciendis optio.,,,Office expenses,9000,Accusantium modi consequuntur eaque consequatur deleniti consequuntur et qui.,T
2024-03-06,REF-6,Petty Cash,Ea consequatur placeat aut et enim.,,,Office expenses,9000,Itaque odio fugiat recusandae.,T
2024-03-07,REF-7,Petty Cash,A expedita consequatur sequi eveniet quos rerum.,,,Office expenses,9000,Quidem doloremque dignissimos totam dolor iure sed necessitatibus optio.,T
2024-03-08,REF-8,Petty Cash,Est libero deleniti animi delectus eligendi necessitatibus expedita fugit.,,,Office expenses,9000,Velit rerum aperiam mollitia ut eius error est quo aut.,T
2024-03-09,REF-9,Petty Cash,Ut dolor tempora quam consequuntur mollitia aut quos consectetur commodi.,,,Office expenses,9000,Culpa architecto ea vero nisi quis voluptas animi.,T
2024-03-10,REF-10,Petty Cash,Nihil hic soluta.,,,Office expenses,9000,Omnis recusandae ducimus vel.,T
2024-03-11,REF-11,Petty Cash,Aspernatur placeat odit asperiores et tempora quam.,,,Office expenses,9000,Sit tempora optio ullam velit beatae architecto et.,T
2024-03-12,REF-12,Petty Cash,Harum soluta sed.,,,Office expenses,9000,Nobis est earum saepe.,T
2024-03-13,REF-13,Petty Cash,Ea quod mollitia non illo dolores voluptatem distinctio.,,,Office expenses,9000,Sit eos dolores autem rerum voluptate quia ipsam.,T
2024-03-14,REF-14,Petty Cash,Et quod distinctio atque.,,,Office expenses,9000,Facilis sed expedita reiciendis.,T
2024-03-15,REF-15,Petty Cash,Omnis delectus tempore.,,,Office expenses,9000,Autem non reprehenderit placeat aut et quo.,T
2024-03-16,REF-16,Petty Cash,Dolores optio qui dolore quia aut explicabo eaque.,,,Office expenses,9000,Odit dolores ut.,T
2024-03-17,REF-17,Petty Cash,Odit quibusdam sunt in a quod error.,,,Office expenses,9000,Quo explicabo quae dolor enim nisi voluptas id et temporibus.,T
2024-03-18,REF-18,Petty Cash,Hic quibusdam officiis voluptatem facilis repellat molestiae non.,,,Office expenses,9000,Quo sit ea et itaque error.,T
2024-03-19,REF-19,Petty Cash,Dolor doloremque quia qui.,,,Office expenses,9000,Ut deleniti laboriosam et.,T
2024-03-20,REF-20,Petty Cash,Ad enim repellat sed et vero aliquid.,,,Office expenses,9000,Error in voluptas non quae quibusdam id excepturi illo neque.,T
2024-03-21,REF-21,Petty Cash,Doloribus ut excepturi.,,,Office expenses,9000,Sint magni et reiciendis harum praesentium vero sit blanditiis.,T
2024-03-22,REF-22,Petty Cash,Id rerum sunt et.,,,Office expenses,9000,Autem magnam eum error ex sunt temporibus exercitationem ullam est.,T
1 Payment Date Reference No. Payment Account Description Currency Code Exchange Rate Expense Account Amount Line Description Publish
2 2024-03-01 REF-1 Petty Cash Vel et dolorem architecto veniam. Office expenses 9000 Voluptates voluptas corporis vel. T
3 2024-03-02 REF-2 Petty Cash Id est molestias. Office expenses 9000 Eos voluptatem cumque et voluptate reiciendis. T
4 2024-03-03 REF-3 Petty Cash Quam cupiditate at nihil dicta dignissimos non fugit illo. Office expenses 9000 Hic alias rerum sed commodi dolores sint animi perferendis. T
5 2024-03-04 REF-4 Petty Cash Et voluptatem consequatur corrupti beatae sit. Office expenses 9000 Exercitationem impedit praesentium et eaque. T
6 2024-03-05 REF-5 Petty Cash Illo aut ad id et non error et reiciendis optio. Office expenses 9000 Accusantium modi consequuntur eaque consequatur deleniti consequuntur et qui. T
7 2024-03-06 REF-6 Petty Cash Ea consequatur placeat aut et enim. Office expenses 9000 Itaque odio fugiat recusandae. T
8 2024-03-07 REF-7 Petty Cash A expedita consequatur sequi eveniet quos rerum. Office expenses 9000 Quidem doloremque dignissimos totam dolor iure sed necessitatibus optio. T
9 2024-03-08 REF-8 Petty Cash Est libero deleniti animi delectus eligendi necessitatibus expedita fugit. Office expenses 9000 Velit rerum aperiam mollitia ut eius error est quo aut. T
10 2024-03-09 REF-9 Petty Cash Ut dolor tempora quam consequuntur mollitia aut quos consectetur commodi. Office expenses 9000 Culpa architecto ea vero nisi quis voluptas animi. T
11 2024-03-10 REF-10 Petty Cash Nihil hic soluta. Office expenses 9000 Omnis recusandae ducimus vel. T
12 2024-03-11 REF-11 Petty Cash Aspernatur placeat odit asperiores et tempora quam. Office expenses 9000 Sit tempora optio ullam velit beatae architecto et. T
13 2024-03-12 REF-12 Petty Cash Harum soluta sed. Office expenses 9000 Nobis est earum saepe. T
14 2024-03-13 REF-13 Petty Cash Ea quod mollitia non illo dolores voluptatem distinctio. Office expenses 9000 Sit eos dolores autem rerum voluptate quia ipsam. T
15 2024-03-14 REF-14 Petty Cash Et quod distinctio atque. Office expenses 9000 Facilis sed expedita reiciendis. T
16 2024-03-15 REF-15 Petty Cash Omnis delectus tempore. Office expenses 9000 Autem non reprehenderit placeat aut et quo. T
17 2024-03-16 REF-16 Petty Cash Dolores optio qui dolore quia aut explicabo eaque. Office expenses 9000 Odit dolores ut. T
18 2024-03-17 REF-17 Petty Cash Odit quibusdam sunt in a quod error. Office expenses 9000 Quo explicabo quae dolor enim nisi voluptas id et temporibus. T
19 2024-03-18 REF-18 Petty Cash Hic quibusdam officiis voluptatem facilis repellat molestiae non. Office expenses 9000 Quo sit ea et itaque error. T
20 2024-03-19 REF-19 Petty Cash Dolor doloremque quia qui. Office expenses 9000 Ut deleniti laboriosam et. T
21 2024-03-20 REF-20 Petty Cash Ad enim repellat sed et vero aliquid. Office expenses 9000 Error in voluptas non quae quibusdam id excepturi illo neque. T
22 2024-03-21 REF-21 Petty Cash Doloribus ut excepturi. Office expenses 9000 Sint magni et reiciendis harum praesentium vero sit blanditiis. T
23 2024-03-22 REF-22 Petty Cash Id rerum sunt et. Office expenses 9000 Autem magnam eum error ex sunt temporibus exercitationem ullam est. T

View File

@@ -0,0 +1,123 @@
Date,Amount,Description,Payee
2024-07-23,-48.25,CREDIT CARD PURCHASE SMART AND FINAL #1 ANAHEIM CA DATE 12/14 15277301931256 9 CARD 5,
2024-08-21,-21.77,PURCHASE AUTHORIZED ON 05/27 ROYAL FARMS 100 MONUMENT AVE A P NATIONAL HARBOR MD 0846248421604 CARD 44,
2024-08-21,-58,72116609 POS PURCHASE EARNIN RE SC 6 721582259,
2024-08-21,-70.61,Dunkin' Donuts,
2024-08-20,-52.34,Uber Eats,
2024-08-19,-15.47,Panera Bread,
2024-08-19,-4.79,5 PURCHASE-SIG DENNY'S 366992 EUGENE OR 6 039488,
2024-08-18,-186,American Airlines,
2024-08-18,-3,3947558 VISA PURCHASE PLAYSTUD 07057808 TAYLOR MI 8840321 748,
2024-08-18,-9.95,Bojangles,
2024-08-15,-134,GrubHub,
2024-08-15,-91.53,671 POS PURCHASE EARNIN RE SC 9671543 349619,
2024-08-15,-4.78,Popeyes,
2024-08-14,496,CASH DEPOSIT,
2024-08-14,-97.67,APPLE 857979823 NEWKIRK #4,
2024-08-07,-2.81,POS PUR 449399193 04/07 TIMESTAMP THE PIZZA PLACE 4205 NEW YORK NY 634330,
2024-08-06,-4.27,QUEENS BAR 35 E GRAND RIVER AVE #9 DETROIT MI CARD 29602991,
2024-08-06,-6.28,Walmart,
2024-08-06,-20.52,60904 PURCHASE-SIG 09/21 TIMESTAMP UPLIFT RE 9123348 562542 SC 63432961 3968766,
2024-08-06,-12.2,UBER 588639690 RIDE 05/12 CA 12095 DEBIT CARD PURCHASE 04/04 TIMESTAMP 8102241,
2024-08-05,-5.58,WITHDRAWAL 02178293119 POS POUR CHOICES,
2024-08-05,-25.98,Planet Fitness,
2024-08-05,-20,CASH APP TRANSFER,
2024-08-04,-38,WITHDRAWAL DEBIT CARD CONSUMER DEBIT PULSZ 252-291-2362 VA DATE 04/12 23978676735612 63546108 CARD 94353,
2024-08-04,-19,CASH APP TRANSFER,
2024-08-04,-3.25,MICROSOFT 979333884,
2024-08-03,-16,TOPGOLF 1010 GREENWOOD BLVD,
2024-08-03,-59.52,EFT DEBIT MICROSOFT XBOX CA 830 08/03 TIMESTAMP,
2024-08-03,-145.09,Venmo,
2024-08-03,-76.02,Albertsons,
2024-08-03,-9.79,STOP & SHOP #25402 WEST CALDWELL MODATE 01/24 31772803806094 17096869 CARD 34321 WITHDRAWAL DEBIT CARD,
2024-08-02,-103.44,Dunkin' Donuts,
2024-08-02,-72,Uber Eats,
2024-08-02,-143.93,Food Lion,
2024-08-02,-128.12,McDonald's,
2024-07-31,-37.47,CHECKCARD 538036 CLEO AI IN MOUNTAIN VIEWCA 172788892 RECURRING,
2024-07-30,-162.69,McDonald's,
2024-07-29,95,Brigit XX/XX #406735377 PMNT RCVD Brigit,
2024-07-29,-45.47,Starbucks,
2024-07-29,-595.11,INTERAC PURCHASE - 67200 TARGET #052,
2024-07-28,-89,TRANSFER PAYPAL ADD TO BALANCE INTERNET PAYMENT,
2024-07-27,-6.04,Krispy Kreme,
2024-07-27,-66.63,McDonald's,
2024-07-26,-133.56,CARD PURCHASE PAYBYPHONE 804665947 11/19,
2024-07-26,-10.02,70252237 AMAZON - LEN N,
2024-07-26,-5,BLAZE PIZZA #31 SIG PUR 9906,
2024-07-25,-30.9,CITGO,
2024-07-25,-69,Tropical Smoothie Cafe,
2024-07-24,-744,Internal Revenue Service,
2024-07-24,-15.61,Walmart,
2024-08-04,-38,WITHDRAWAL DEBIT CARD CONSUMER DEBIT,
2024-08-05,-5.58,WITHDRAWAL POS POUR,
2024-08-06,-6.28,Walmart,
2024-07-24,-15.61,Walmart,
2024-08-03,-145.09,Venmo,
2024-08-20,-52.34,Uber Eats,
2024-08-02,-72,Uber Eats,
2024-07-25,-69,Tropical Smoothie Cafe,
2024-07-28,-89,TRANSFER ADD TO BALANCE INTERNET PAYMENT,
2024-08-03,-76.02,Albertsons,
2024-08-18,-186,American Airlines,
2024-08-15,-91.53,POS PURCHASE EARNIN RE SC 9671543 349619,
2024-07-29,-95,PMNT RCVD Brigit,
2024-08-04,-19,CASH APP TRANSFER,
2024-08-05,-20,CASH APP TRANSFER,
2024-08-14,496,CASH DEPOSIT,
2024-07-31,-37.47,CHECKCARD 538036 CLEO AI IN MOUNTAIN VIEWCA,
2024-07-25,-30.9,Citgo,
2024-08-18,-9.95,Bojangles,
2024-07-24,-744,Internal Revenue Service,
2024-07-27,-6.04,Krispy Kreme,
2024-07-27,-66.63,McDonald's,
2024-07-30,-162.69,McDonald's,
2024-08-02,-128.12,McDonald's,
2024-08-04,-3.25,MICROSOFT,
2024-08-19,-15.47,Panera Bread,
2024-08-05,-25.98,Planet Fitness,
2024-08-15,-4.78,Popeyes,
2024-08-07,-2.81,POS PUR,
2024-08-21,-21.77,PURCHASE AUTHORIZED ON 05/27,
2024-07-29,-45.47,Starbucks,
2024-08-03,-9.79,WITHDRAWAL DEBIT CARD,
2024-08-03,-16,TOPGOLF 1010 GREENWOOD BLVD,
2024-08-04,-38,WITHDRAWAL DEBIT CARD CONSUMER DEBIT,
2024-08-05,-5.58,WITHDRAWAL POS POUR,
2024-08-06,-6.28,Walmart,
2024-07-24,-15.61,Walmart,
2024-08-03,-145.09,Venmo,
2024-08-20,-52.34,Uber Eats,
2024-08-02,-72,Uber Eats,
2024-07-25,-69,Tropical Smoothie Cafe,
2024-07-28,-89,TRANSFER ADD TO BALANCE INTERNET PAYMENT,
2024-08-03,-76.02,Albertsons,
2024-08-18,-186,American Airlines,
2024-08-15,-91.53,POS PURCHASE EARNIN RE SC 9671543 349619,
2024-07-29,-95,PMNT RCVD Brigit,
2024-08-04,-19,CASH APP TRANSFER,
2024-08-05,-20,CASH APP TRANSFER,
2024-08-14,496,CASH DEPOSIT,
2024-07-31,-37.47,CHECKCARD 538036 CLEO AI IN MOUNTAIN VIEWCA,
2024-07-25,-30.9,Citgo,
2024-08-18,-9.95,Bojangles,
2024-07-24,-744,Internal Revenue Service,
2024-07-27,-6.04,Krispy Kreme,
2024-07-27,-66.63,McDonald's,
2024-07-30,-162.69,McDonald's,
2024-08-02,-128.12,McDonald's,
2024-08-04,-3.25,MICROSOFT,
2024-08-19,-15.47,Panera Bread,
2024-08-05,-25.98,Planet Fitness,
2024-08-15,-4.78,Popeyes,
2024-08-07,-2.81,POS PUR,
2024-08-21,-21.77,PURCHASE AUTHORIZED ON 05/27,
2024-07-29,-45.47,Starbucks,
2024-08-03,-9.79,WITHDRAWAL DEBIT CARD,
2024-08-03,-16,TOPGOLF 1010 GREENWOOD BLVD,
2024-08-04,-38,WITHDRAWAL DEBIT CARD CONSUMER DEBIT,
2024-08-05,-5.58,WITHDRAWAL POS POUR,
2024-08-04,-3.25,MICROSOFT,
2024-08-07,-2.81,POS PUR,
2024-08-21,-21.77,PURCHASE AUTHORIZED ON 05/27,
2024-08-03,-9.79,WITHDRAWAL DEBIT CARD,
1 Date Amount Description Payee
2 2024-07-23 -48.25 CREDIT CARD PURCHASE SMART AND FINAL #1 ANAHEIM CA DATE 12/14 15277301931256 9 CARD 5
3 2024-08-21 -21.77 PURCHASE AUTHORIZED ON 05/27 ROYAL FARMS 100 MONUMENT AVE A P NATIONAL HARBOR MD 0846248421604 CARD 44
4 2024-08-21 -58 72116609 POS PURCHASE EARNIN RE SC 6 721582259
5 2024-08-21 -70.61 Dunkin' Donuts
6 2024-08-20 -52.34 Uber Eats
7 2024-08-19 -15.47 Panera Bread
8 2024-08-19 -4.79 5 PURCHASE-SIG DENNY'S 366992 EUGENE OR 6 039488
9 2024-08-18 -186 American Airlines
10 2024-08-18 -3 3947558 VISA PURCHASE PLAYSTUD 07057808 TAYLOR MI 8840321 748
11 2024-08-18 -9.95 Bojangles
12 2024-08-15 -134 GrubHub
13 2024-08-15 -91.53 671 POS PURCHASE EARNIN RE SC 9671543 349619
14 2024-08-15 -4.78 Popeyes
15 2024-08-14 496 CASH DEPOSIT
16 2024-08-14 -97.67 APPLE 857979823 NEWKIRK #4
17 2024-08-07 -2.81 POS PUR 449399193 04/07 TIMESTAMP THE PIZZA PLACE 4205 NEW YORK NY 634330
18 2024-08-06 -4.27 QUEENS BAR 35 E GRAND RIVER AVE #9 DETROIT MI CARD 29602991
19 2024-08-06 -6.28 Walmart
20 2024-08-06 -20.52 60904 PURCHASE-SIG 09/21 TIMESTAMP UPLIFT RE 9123348 562542 SC 63432961 3968766
21 2024-08-06 -12.2 UBER 588639690 RIDE 05/12 CA 12095 DEBIT CARD PURCHASE 04/04 TIMESTAMP 8102241
22 2024-08-05 -5.58 WITHDRAWAL 02178293119 POS POUR CHOICES
23 2024-08-05 -25.98 Planet Fitness
24 2024-08-05 -20 CASH APP TRANSFER
25 2024-08-04 -38 WITHDRAWAL DEBIT CARD CONSUMER DEBIT PULSZ 252-291-2362 VA DATE 04/12 23978676735612 63546108 CARD 94353
26 2024-08-04 -19 CASH APP TRANSFER
27 2024-08-04 -3.25 MICROSOFT 979333884
28 2024-08-03 -16 TOPGOLF 1010 GREENWOOD BLVD
29 2024-08-03 -59.52 EFT DEBIT MICROSOFT XBOX CA 830 08/03 TIMESTAMP
30 2024-08-03 -145.09 Venmo
31 2024-08-03 -76.02 Albertsons
32 2024-08-03 -9.79 STOP & SHOP #25402 WEST CALDWELL MODATE 01/24 31772803806094 17096869 CARD 34321 WITHDRAWAL DEBIT CARD
33 2024-08-02 -103.44 Dunkin' Donuts
34 2024-08-02 -72 Uber Eats
35 2024-08-02 -143.93 Food Lion
36 2024-08-02 -128.12 McDonald's
37 2024-07-31 -37.47 CHECKCARD 538036 CLEO AI IN MOUNTAIN VIEWCA 172788892 RECURRING
38 2024-07-30 -162.69 McDonald's
39 2024-07-29 95 Brigit XX/XX #406735377 PMNT RCVD Brigit
40 2024-07-29 -45.47 Starbucks
41 2024-07-29 -595.11 INTERAC PURCHASE - 67200 TARGET #052
42 2024-07-28 -89 TRANSFER PAYPAL ADD TO BALANCE INTERNET PAYMENT
43 2024-07-27 -6.04 Krispy Kreme
44 2024-07-27 -66.63 McDonald's
45 2024-07-26 -133.56 CARD PURCHASE PAYBYPHONE 804665947 11/19
46 2024-07-26 -10.02 70252237 AMAZON - LEN N
47 2024-07-26 -5 BLAZE PIZZA #31 SIG PUR 9906
48 2024-07-25 -30.9 CITGO
49 2024-07-25 -69 Tropical Smoothie Cafe
50 2024-07-24 -744 Internal Revenue Service
51 2024-07-24 -15.61 Walmart
52 2024-08-04 -38 WITHDRAWAL DEBIT CARD CONSUMER DEBIT
53 2024-08-05 -5.58 WITHDRAWAL POS POUR
54 2024-08-06 -6.28 Walmart
55 2024-07-24 -15.61 Walmart
56 2024-08-03 -145.09 Venmo
57 2024-08-20 -52.34 Uber Eats
58 2024-08-02 -72 Uber Eats
59 2024-07-25 -69 Tropical Smoothie Cafe
60 2024-07-28 -89 TRANSFER ADD TO BALANCE INTERNET PAYMENT
61 2024-08-03 -76.02 Albertsons
62 2024-08-18 -186 American Airlines
63 2024-08-15 -91.53 POS PURCHASE EARNIN RE SC 9671543 349619
64 2024-07-29 -95 PMNT RCVD Brigit
65 2024-08-04 -19 CASH APP TRANSFER
66 2024-08-05 -20 CASH APP TRANSFER
67 2024-08-14 496 CASH DEPOSIT
68 2024-07-31 -37.47 CHECKCARD 538036 CLEO AI IN MOUNTAIN VIEWCA
69 2024-07-25 -30.9 Citgo
70 2024-08-18 -9.95 Bojangles
71 2024-07-24 -744 Internal Revenue Service
72 2024-07-27 -6.04 Krispy Kreme
73 2024-07-27 -66.63 McDonald's
74 2024-07-30 -162.69 McDonald's
75 2024-08-02 -128.12 McDonald's
76 2024-08-04 -3.25 MICROSOFT
77 2024-08-19 -15.47 Panera Bread
78 2024-08-05 -25.98 Planet Fitness
79 2024-08-15 -4.78 Popeyes
80 2024-08-07 -2.81 POS PUR
81 2024-08-21 -21.77 PURCHASE AUTHORIZED ON 05/27
82 2024-07-29 -45.47 Starbucks
83 2024-08-03 -9.79 WITHDRAWAL DEBIT CARD
84 2024-08-03 -16 TOPGOLF 1010 GREENWOOD BLVD
85 2024-08-04 -38 WITHDRAWAL DEBIT CARD CONSUMER DEBIT
86 2024-08-05 -5.58 WITHDRAWAL POS POUR
87 2024-08-06 -6.28 Walmart
88 2024-07-24 -15.61 Walmart
89 2024-08-03 -145.09 Venmo
90 2024-08-20 -52.34 Uber Eats
91 2024-08-02 -72 Uber Eats
92 2024-07-25 -69 Tropical Smoothie Cafe
93 2024-07-28 -89 TRANSFER ADD TO BALANCE INTERNET PAYMENT
94 2024-08-03 -76.02 Albertsons
95 2024-08-18 -186 American Airlines
96 2024-08-15 -91.53 POS PURCHASE EARNIN RE SC 9671543 349619
97 2024-07-29 -95 PMNT RCVD Brigit
98 2024-08-04 -19 CASH APP TRANSFER
99 2024-08-05 -20 CASH APP TRANSFER
100 2024-08-14 496 CASH DEPOSIT
101 2024-07-31 -37.47 CHECKCARD 538036 CLEO AI IN MOUNTAIN VIEWCA
102 2024-07-25 -30.9 Citgo
103 2024-08-18 -9.95 Bojangles
104 2024-07-24 -744 Internal Revenue Service
105 2024-07-27 -6.04 Krispy Kreme
106 2024-07-27 -66.63 McDonald's
107 2024-07-30 -162.69 McDonald's
108 2024-08-02 -128.12 McDonald's
109 2024-08-04 -3.25 MICROSOFT
110 2024-08-19 -15.47 Panera Bread
111 2024-08-05 -25.98 Planet Fitness
112 2024-08-15 -4.78 Popeyes
113 2024-08-07 -2.81 POS PUR
114 2024-08-21 -21.77 PURCHASE AUTHORIZED ON 05/27
115 2024-07-29 -45.47 Starbucks
116 2024-08-03 -9.79 WITHDRAWAL DEBIT CARD
117 2024-08-03 -16 TOPGOLF 1010 GREENWOOD BLVD
118 2024-08-04 -38 WITHDRAWAL DEBIT CARD CONSUMER DEBIT
119 2024-08-05 -5.58 WITHDRAWAL POS POUR
120 2024-08-04 -3.25 MICROSOFT
121 2024-08-07 -2.81 POS PUR
122 2024-08-21 -21.77 PURCHASE AUTHORIZED ON 05/27
123 2024-08-03 -9.79 WITHDRAWAL DEBIT CARD

View File

@@ -0,0 +1,6 @@
Customer Type,First Name,Last Name,Company Name,Display Name,Email,Personal Phone Number,Work Phone Number,Website,Opening Balance,Opening Balance At,Opening Balance Ex. Rate,Currency,Active,Note,Billing Address 1,Billing Address 2,Billing Address City,Billing Address Country,Billing Address Phone,Billing Address Postcode,Billing Address State,Shipping Address 1,Shipping Address 2,Shipping Address City,Shipping Address Country,Shipping Address Phone,Shipping Address Postcode,Shipping Address State
Business,Nicolette,Schamberger,Homenick - Hane,Rowland Rowe,cicero86@yahoo.com,811-603-2235,906-993-5190,http://google.com,54302.23,2022-02-02,2,LYD,F,Doloribus autem optio temporibus dolores mollitia sit.,862 Jessika Well,1091 Dorthy Mount,Deckowfort,Ghana,825-011-5207,38228,Oregon,37626 Thiel Villages,132 Batz Avenue,Pagacburgh,Albania,171-546-3701,13709,Georgia
Business,Hermann,Crooks,Veum - Schaefer,Harley Veum,immanuel56@hotmail.com,449-780-9999,970-473-5785,http://google.com,54302.23,2022-02-02,2,LYD,T,Doloribus dolore dolor dicta vitae in fugit nisi quibusdam.,532 Simonis Spring,3122 Nicolas Inlet,East Matteofort,Holy See (Vatican City State),366-084-8629,41607,Montana,2889 Tremblay Plaza,71355 Kutch Isle,D'Amorehaven,Monaco,614-189-3328,09634-0435,Nevada
Business,Nellie,Gulgowski,"Boyle, Heller and Jones",Randall Kohler,anibal_frami@yahoo.com,498-578-0740,394-550-6827,http://google.com,54302.23,2022-02-02,2,LYD,T,Vero quibusdam rem fugit aperiam est modi.,214 Sauer Villages,30687 Kacey Square,Jayceborough,Benin,332-820-1127,16425-3887,Mississippi,562 Diamond Loaf,9595 Satterfield Trafficway,Alexandrinefort,Puerto Rico,776-500-8456,30258,South Dakota
Business,Stone,Jerde,"Cassin, Casper and Maggio",Clint McLaughlin,nathanael22@yahoo.com,562-790-6059,686-838-0027,http://google.com,54302.23,2022-02-02,2,LYD,F,Quis cumque molestias rerum.,22590 Cathy Harbor,24493 Brycen Brooks,Elnorashire,Andorra,701-852-8005,5680,Nevada,5355 Erdman Bridge,421 Jeanette Camp,East Philip,Venezuela,426-119-0858,34929-0501,Tennessee
Individual,Lempi,Kling,"Schamberger, O'Connell and Bechtelar",Alexie Barton,eulah.kreiger@hotmail.com,745-756-1063,965-150-1945,http://google.com,54302.23,2022-02-02,2,LYD,F,Maxime laboriosam hic voluptate maiores est officia.,0851 Jones Flat,845 Bailee Drives,Kamrenport,Niger,220-125-0608,30311,Delaware,929 Ferry Row,020 Adam Plaza,West Carmellaside,Ghana,053-333-6679,79221-4681,Illinois
1 Customer Type First Name Last Name Company Name Display Name Email Personal Phone Number Work Phone Number Website Opening Balance Opening Balance At Opening Balance Ex. Rate Currency Active Note Billing Address 1 Billing Address 2 Billing Address City Billing Address Country Billing Address Phone Billing Address Postcode Billing Address State Shipping Address 1 Shipping Address 2 Shipping Address City Shipping Address Country Shipping Address Phone Shipping Address Postcode Shipping Address State
2 Business Nicolette Schamberger Homenick - Hane Rowland Rowe cicero86@yahoo.com 811-603-2235 906-993-5190 http://google.com 54302.23 2022-02-02 2 LYD F Doloribus autem optio temporibus dolores mollitia sit. 862 Jessika Well 1091 Dorthy Mount Deckowfort Ghana 825-011-5207 38228 Oregon 37626 Thiel Villages 132 Batz Avenue Pagacburgh Albania 171-546-3701 13709 Georgia
3 Business Hermann Crooks Veum - Schaefer Harley Veum immanuel56@hotmail.com 449-780-9999 970-473-5785 http://google.com 54302.23 2022-02-02 2 LYD T Doloribus dolore dolor dicta vitae in fugit nisi quibusdam. 532 Simonis Spring 3122 Nicolas Inlet East Matteofort Holy See (Vatican City State) 366-084-8629 41607 Montana 2889 Tremblay Plaza 71355 Kutch Isle D'Amorehaven Monaco 614-189-3328 09634-0435 Nevada
4 Business Nellie Gulgowski Boyle, Heller and Jones Randall Kohler anibal_frami@yahoo.com 498-578-0740 394-550-6827 http://google.com 54302.23 2022-02-02 2 LYD T Vero quibusdam rem fugit aperiam est modi. 214 Sauer Villages 30687 Kacey Square Jayceborough Benin 332-820-1127 16425-3887 Mississippi 562 Diamond Loaf 9595 Satterfield Trafficway Alexandrinefort Puerto Rico 776-500-8456 30258 South Dakota
5 Business Stone Jerde Cassin, Casper and Maggio Clint McLaughlin nathanael22@yahoo.com 562-790-6059 686-838-0027 http://google.com 54302.23 2022-02-02 2 LYD F Quis cumque molestias rerum. 22590 Cathy Harbor 24493 Brycen Brooks Elnorashire Andorra 701-852-8005 5680 Nevada 5355 Erdman Bridge 421 Jeanette Camp East Philip Venezuela 426-119-0858 34929-0501 Tennessee
6 Individual Lempi Kling Schamberger, O'Connell and Bechtelar Alexie Barton eulah.kreiger@hotmail.com 745-756-1063 965-150-1945 http://google.com 54302.23 2022-02-02 2 LYD F Maxime laboriosam hic voluptate maiores est officia. 0851 Jones Flat 845 Bailee Drives Kamrenport Niger 220-125-0608 30311 Delaware 929 Ferry Row 020 Adam Plaza West Carmellaside Ghana 053-333-6679 79221-4681 Illinois

View File

@@ -0,0 +1,61 @@
Item Type,Item Name,Item Code,Sellable,Purchasable,Cost Price,Sell Price,Cost Account,Sell Account,Inventory Account,Sell Description,Purchase Description,Category,Note,Active
Inventory,Amoxicillin and Clavulanatea,1000,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,At dolor est non tempore et quisquam.,TRUE
Inventory,Azithromycin,1001,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Id perspiciatis at adipisci minus accusamus dolor iure dolore.,TRUE
Inventory,Marks - Carroll,1002,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Odio odio minus similique.,TRUE
Inventory,"VonRueden, Ruecker and Hettinger",1003,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Quibusdam dolores illo.,TRUE
Inventory,Aimovig SureClick Autoinjector,1004,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Labore atque quo nam natus ducimus.,TRUE
Inventory,Romaguera Group,1005,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Sit et aut rem necessitatibus.,TRUE
Inventory,Thompson - Reichert,1006,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Non non fuga esse fugit dolor soluta vel a.,TRUE
Inventory,AirDuo Digihaler with eModule,1007,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Error ut est soluta quos et qui.,TRUE
Inventory,"Reichert, Sanford and Shanahan",1008,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Nesciunt laboriosam nobis porro numquam hic expedita vel quod praesentium.,TRUE
Inventory,Crooks - Fay,1009,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Amet magni architecto voluptas itaque.,TRUE
Inventory,Becker - Kozey,1010,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Provident consequatur quos qui explicabo dicta nam.,TRUE
Inventory,Robel - Weber,1011,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Quia cum eos rerum odio omnis quasi.,TRUE
Inventory,"Runte, Johns and Konopelski",1012,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Soluta et et accusantium corrupti autem repellendus assumenda fugit.,TRUE
Inventory,McCullough - Beer,1013,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Quo quod sunt distinctio aliquid accusantium.,TRUE
Inventory,"Hintz, Wisozk and Mills",1014,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Asperiores esse at quos veritatis voluptas officiis.,TRUE
Inventory,"Zieme, Crist and Abbott",1015,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Ea ut qui architecto voluptates error.,TRUE
Inventory,Kiehn - Cormier,1016,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Libero sit impedit sint qui voluptatum id qui sed.,TRUE
Inventory,"Jast, Carter and Reynolds",1017,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Sint sunt quaerat nisi voluptate praesentium vero labore veniam quia.,TRUE
Inventory,Stehr Inc,1018,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Voluptas aut ipsum et iste.,TRUE
Inventory,"Friesen, Hamill and Hessel",1019,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Neque tenetur minima amet aut optio et recusandae vel ad.,TRUE
Inventory,Lemke - Hayes,1020,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Deleniti enim autem corrupti fuga quibusdam non.,TRUE
Inventory,Mirtazapine,1021,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Molestiae quia asperiores praesentium et voluptas iste sit et accusantium.,TRUE
Inventory,Medroxyprogesterone,1022,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Est quia omnis at.,TRUE
Inventory,Purdy and Sons,1023,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Veniam eos quibusdam neque consectetur eius aliquam.,TRUE
Inventory,"Zemlak, Kassulke and Veum",1024,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Vitae optio odit.,TRUE
Inventory,Kris LLC,1025,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Libero voluptatibus voluptatem quo.,TRUE
Inventory,"Jaskolski, Parker and Blanda",1026,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Laborum optio est voluptas dolores sunt voluptates.,TRUE
Inventory,Roberts Kilback,1027,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Ut illo molestiae dolore recusandae aut sequi molestiae fugit eum.,TRUE
Inventory,Olson Daugherty,1028,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Non est aut sit nulla nisi labore commodi delectus.,TRUE
Inventory,Hermann Inc,1029,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Commodi maxime minus dicta quia.,TRUE
Inventory,"Rowe, Nolan and Schaefer",1030,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Quos et est eum odit quam omnis velit impedit tempora.,TRUE
Inventory,Cole - Lesch,1031,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Aut accusantium non.,TRUE
Inventory,"Emmerich, Prohaska and Schimmel",1032,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Doloribus aut qui sequi.,TRUE
Inventory,"Stracke, Champlin and Bayer",1033,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Quisquam odio et et quod eum necessitatibus quaerat.,TRUE
Inventory,Spinka Okuneva,1034,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Rerum unde neque sit ut aut voluptas eum.,TRUE
Inventory,Swaniawski Muller,1035,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Quia dolore minus voluptatibus modi.,TRUE
Inventory,Emard Satterfield,1036,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Nobis et nulla alias.,TRUE
Inventory,"Treutel, Muller and Sipes",1037,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Sit perspiciatis voluptate qui eos.,TRUE
Inventory,Cole and Sons,1038,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Qui sint ab iusto.,TRUE
Inventory,"Ullrich, Murazik and Roob",1039,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Explicabo sed maiores.,TRUE
Inventory,Dare and Sons,1040,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Aut eveniet omnis dolores labore qui delectus repellat.,TRUE
Inventory,Trantow and Sons,1041,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Animi rerum quaerat qui voluptas.,TRUE
Inventory,Dooley Price,1042,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Reiciendis beatae delectus qui corporis beatae autem modi laudantium.,TRUE
Inventory,"Shanahan, Considine and Towne",1043,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Molestiae nihil delectus eos.,TRUE
Inventory,"Moen, Mohr and Reilly",1044,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Dolor odio soluta eaque consequatur rerum iste vel.,TRUE
Inventory,Price Bradtke,1045,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Beatae autem illo ea alias ipsum nobis.,TRUE
Inventory,Fadel Toy,1046,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Et molestiae eum ut dolores.,TRUE
Inventory,Homenick Inc,1047,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Officia repellendus laboriosam iste quidem explicabo nemo quasi aliquam distinctio.,TRUE
Inventory,Witting Lemke,1048,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Nihil qui voluptatem unde.,TRUE
Inventory,Gerlach Thompson,1049,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Quo quas debitis vel.,TRUE
Inventory,Schaefer Thompson,1050,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Minima nobis voluptas autem aut adipisci tenetur.,TRUE
Inventory,"Kovacek, Schuster and Kemmer",1051,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Aspernatur earum praesentium laudantium velit.,TRUE
Inventory,Treutel Stanton,1052,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Laboriosam repellendus quisquam labore ipsum et.,TRUE
Inventory,Bartell and Sons,1053,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Sed voluptatem consequatur reprehenderit ab aut molestiae.,TRUE
Inventory,"Bergnaum, Murray and McGlynn",1054,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Ullam in ut molestiae non eveniet et totam dolor.,TRUE
Inventory,"Wilkinson, Schowalter and Lindgren",1055,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Distinctio rerum iusto explicabo fugiat doloremque aut omnis at est.,TRUE
Inventory,"Glover, Zemlak and Kerluke",1056,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Eum at laboriosam aut.,TRUE
Inventory,Durgan Kirlin,1057,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Reprehenderit sunt expedita voluptatum nobis deleniti aliquam numquam quas.,TRUE
Inventory,Towne Crooks,1058,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Aliquam animi libero modi quisquam voluptas fugiat.,TRUE
Inventory,Wuckert McGlynn,1059,T,T,10000,1000,Cost of Goods Sold,Other Income,Inventory Asset,Description ....,Description ....,sdafasdfsadf,Quidem ut et ut reprehenderit.,TRUE
1 Item Type Item Name Item Code Sellable Purchasable Cost Price Sell Price Cost Account Sell Account Inventory Account Sell Description Purchase Description Category Note Active
2 Inventory Amoxicillin and Clavulanatea 1000 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf At dolor est non tempore et quisquam. TRUE
3 Inventory Azithromycin 1001 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Id perspiciatis at adipisci minus accusamus dolor iure dolore. TRUE
4 Inventory Marks - Carroll 1002 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Odio odio minus similique. TRUE
5 Inventory VonRueden, Ruecker and Hettinger 1003 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Quibusdam dolores illo. TRUE
6 Inventory Aimovig SureClick Autoinjector 1004 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Labore atque quo nam natus ducimus. TRUE
7 Inventory Romaguera Group 1005 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Sit et aut rem necessitatibus. TRUE
8 Inventory Thompson - Reichert 1006 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Non non fuga esse fugit dolor soluta vel a. TRUE
9 Inventory AirDuo Digihaler with eModule 1007 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Error ut est soluta quos et qui. TRUE
10 Inventory Reichert, Sanford and Shanahan 1008 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Nesciunt laboriosam nobis porro numquam hic expedita vel quod praesentium. TRUE
11 Inventory Crooks - Fay 1009 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Amet magni architecto voluptas itaque. TRUE
12 Inventory Becker - Kozey 1010 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Provident consequatur quos qui explicabo dicta nam. TRUE
13 Inventory Robel - Weber 1011 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Quia cum eos rerum odio omnis quasi. TRUE
14 Inventory Runte, Johns and Konopelski 1012 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Soluta et et accusantium corrupti autem repellendus assumenda fugit. TRUE
15 Inventory McCullough - Beer 1013 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Quo quod sunt distinctio aliquid accusantium. TRUE
16 Inventory Hintz, Wisozk and Mills 1014 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Asperiores esse at quos veritatis voluptas officiis. TRUE
17 Inventory Zieme, Crist and Abbott 1015 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Ea ut qui architecto voluptates error. TRUE
18 Inventory Kiehn - Cormier 1016 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Libero sit impedit sint qui voluptatum id qui sed. TRUE
19 Inventory Jast, Carter and Reynolds 1017 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Sint sunt quaerat nisi voluptate praesentium vero labore veniam quia. TRUE
20 Inventory Stehr Inc 1018 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Voluptas aut ipsum et iste. TRUE
21 Inventory Friesen, Hamill and Hessel 1019 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Neque tenetur minima amet aut optio et recusandae vel ad. TRUE
22 Inventory Lemke - Hayes 1020 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Deleniti enim autem corrupti fuga quibusdam non. TRUE
23 Inventory Mirtazapine 1021 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Molestiae quia asperiores praesentium et voluptas iste sit et accusantium. TRUE
24 Inventory Medroxyprogesterone 1022 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Est quia omnis at. TRUE
25 Inventory Purdy and Sons 1023 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Veniam eos quibusdam neque consectetur eius aliquam. TRUE
26 Inventory Zemlak, Kassulke and Veum 1024 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Vitae optio odit. TRUE
27 Inventory Kris LLC 1025 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Libero voluptatibus voluptatem quo. TRUE
28 Inventory Jaskolski, Parker and Blanda 1026 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Laborum optio est voluptas dolores sunt voluptates. TRUE
29 Inventory Roberts Kilback 1027 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Ut illo molestiae dolore recusandae aut sequi molestiae fugit eum. TRUE
30 Inventory Olson Daugherty 1028 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Non est aut sit nulla nisi labore commodi delectus. TRUE
31 Inventory Hermann Inc 1029 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Commodi maxime minus dicta quia. TRUE
32 Inventory Rowe, Nolan and Schaefer 1030 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Quos et est eum odit quam omnis velit impedit tempora. TRUE
33 Inventory Cole - Lesch 1031 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Aut accusantium non. TRUE
34 Inventory Emmerich, Prohaska and Schimmel 1032 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Doloribus aut qui sequi. TRUE
35 Inventory Stracke, Champlin and Bayer 1033 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Quisquam odio et et quod eum necessitatibus quaerat. TRUE
36 Inventory Spinka Okuneva 1034 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Rerum unde neque sit ut aut voluptas eum. TRUE
37 Inventory Swaniawski Muller 1035 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Quia dolore minus voluptatibus modi. TRUE
38 Inventory Emard Satterfield 1036 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Nobis et nulla alias. TRUE
39 Inventory Treutel, Muller and Sipes 1037 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Sit perspiciatis voluptate qui eos. TRUE
40 Inventory Cole and Sons 1038 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Qui sint ab iusto. TRUE
41 Inventory Ullrich, Murazik and Roob 1039 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Explicabo sed maiores. TRUE
42 Inventory Dare and Sons 1040 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Aut eveniet omnis dolores labore qui delectus repellat. TRUE
43 Inventory Trantow and Sons 1041 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Animi rerum quaerat qui voluptas. TRUE
44 Inventory Dooley Price 1042 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Reiciendis beatae delectus qui corporis beatae autem modi laudantium. TRUE
45 Inventory Shanahan, Considine and Towne 1043 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Molestiae nihil delectus eos. TRUE
46 Inventory Moen, Mohr and Reilly 1044 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Dolor odio soluta eaque consequatur rerum iste vel. TRUE
47 Inventory Price Bradtke 1045 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Beatae autem illo ea alias ipsum nobis. TRUE
48 Inventory Fadel Toy 1046 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Et molestiae eum ut dolores. TRUE
49 Inventory Homenick Inc 1047 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Officia repellendus laboriosam iste quidem explicabo nemo quasi aliquam distinctio. TRUE
50 Inventory Witting Lemke 1048 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Nihil qui voluptatem unde. TRUE
51 Inventory Gerlach Thompson 1049 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Quo quas debitis vel. TRUE
52 Inventory Schaefer Thompson 1050 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Minima nobis voluptas autem aut adipisci tenetur. TRUE
53 Inventory Kovacek, Schuster and Kemmer 1051 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Aspernatur earum praesentium laudantium velit. TRUE
54 Inventory Treutel Stanton 1052 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Laboriosam repellendus quisquam labore ipsum et. TRUE
55 Inventory Bartell and Sons 1053 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Sed voluptatem consequatur reprehenderit ab aut molestiae. TRUE
56 Inventory Bergnaum, Murray and McGlynn 1054 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Ullam in ut molestiae non eveniet et totam dolor. TRUE
57 Inventory Wilkinson, Schowalter and Lindgren 1055 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Distinctio rerum iusto explicabo fugiat doloremque aut omnis at est. TRUE
58 Inventory Glover, Zemlak and Kerluke 1056 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Eum at laboriosam aut. TRUE
59 Inventory Durgan Kirlin 1057 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Reprehenderit sunt expedita voluptatum nobis deleniti aliquam numquam quas. TRUE
60 Inventory Towne Crooks 1058 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Aliquam animi libero modi quisquam voluptas fugiat. TRUE
61 Inventory Wuckert McGlynn 1059 T T 10000 1000 Cost of Goods Sold Other Income Inventory Asset Description .... Description .... sdafasdfsadf Quidem ut et ut reprehenderit. TRUE

View File

@@ -0,0 +1,11 @@
Date,Journal No,Reference No.,Currency Code,Exchange Rate,Journal Type,Description,Credit,Debit,Note,Account,Contact,Publish
2024-02-02,J-100022,REF-10000,,,,Animi quasi qui itaque aut possimus illum est magnam enim.,1000,0,Qui reprehenderit voluptate.,Bank Account,,T
2024-02-02,J-100022,REF-10000,,,,In assumenda dicta autem non est corrupti non et.,0,1000,Omnis tempora qui fugiat neque dolor voluptatem aut repudiandae nihil.,Bank Account,,T
2024-02-01,J-100023,REF-10000,,,,Animi quasi qui itaque aut possimus illum est magnam enim.,1400,0,Qui reprehenderit voluptate.,Bank Account,,T
2024-02-01,J-100023,REF-10000,,,,In assumenda dicta autem non est corrupti non et.,0,1400,Omnis tempora qui fugiat neque dolor voluptatem aut repudiandae nihil.,Bank Account,,T
2024-02-15,J-100024,REF-10000,,,,Animi quasi qui itaque aut possimus illum est magnam enim.,1900,0,Qui reprehenderit voluptate.,Bank Account,,T
2024-02-15,J-100024,REF-10000,,,,In assumenda dicta autem non est corrupti non et.,0,1900,Omnis tempora qui fugiat neque dolor voluptatem aut repudiandae nihil.,Bank Account,,T
2024-02-15,J-100025,REF-10000,,,,Animi quasi qui itaque aut possimus illum est magnam enim.,1900,0,Qui reprehenderit voluptate.,Bank Account,,T
2024-02-15,J-100025,REF-10000,,,,In assumenda dicta autem non est corrupti non et.,0,1900,Omnis tempora qui fugiat neque dolor voluptatem aut repudiandae nihil.,Bank Account,,T
2024-02-15,J-100026,REF-10000,,,,Animi quasi qui itaque aut possimus illum est magnam enim.,3494,0,Qui reprehenderit voluptate.,Bank Account,,T
2024-02-15,J-100026,REF-10000,,,,In assumenda dicta autem non est corrupti non et.,0,3494,Omnis tempora qui fugiat neque dolor voluptatem aut repudiandae nihil.,Bank Account,,T
1 Date Journal No Reference No. Currency Code Exchange Rate Journal Type Description Credit Debit Note Account Contact Publish
2 2024-02-02 J-100022 REF-10000 Animi quasi qui itaque aut possimus illum est magnam enim. 1000 0 Qui reprehenderit voluptate. Bank Account T
3 2024-02-02 J-100022 REF-10000 In assumenda dicta autem non est corrupti non et. 0 1000 Omnis tempora qui fugiat neque dolor voluptatem aut repudiandae nihil. Bank Account T
4 2024-02-01 J-100023 REF-10000 Animi quasi qui itaque aut possimus illum est magnam enim. 1400 0 Qui reprehenderit voluptate. Bank Account T
5 2024-02-01 J-100023 REF-10000 In assumenda dicta autem non est corrupti non et. 0 1400 Omnis tempora qui fugiat neque dolor voluptatem aut repudiandae nihil. Bank Account T
6 2024-02-15 J-100024 REF-10000 Animi quasi qui itaque aut possimus illum est magnam enim. 1900 0 Qui reprehenderit voluptate. Bank Account T
7 2024-02-15 J-100024 REF-10000 In assumenda dicta autem non est corrupti non et. 0 1900 Omnis tempora qui fugiat neque dolor voluptatem aut repudiandae nihil. Bank Account T
8 2024-02-15 J-100025 REF-10000 Animi quasi qui itaque aut possimus illum est magnam enim. 1900 0 Qui reprehenderit voluptate. Bank Account T
9 2024-02-15 J-100025 REF-10000 In assumenda dicta autem non est corrupti non et. 0 1900 Omnis tempora qui fugiat neque dolor voluptatem aut repudiandae nihil. Bank Account T
10 2024-02-15 J-100026 REF-10000 Animi quasi qui itaque aut possimus illum est magnam enim. 3494 0 Qui reprehenderit voluptate. Bank Account T
11 2024-02-15 J-100026 REF-10000 In assumenda dicta autem non est corrupti non et. 0 3494 Omnis tempora qui fugiat neque dolor voluptatem aut repudiandae nihil. Bank Account T

View File

@@ -0,0 +1,50 @@
Invoice No.,Reference No.,Invoice Date,Due Date,Customer,Exchange Rate,Invoice Message,Terms & Conditions,Delivered,Item,Quantity,Rate,Description
B-101,REF-0,2024-04-15,2024-04-17,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-102,REF-1,2024-04-16,2024-04-18,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-103,REF-2,2024-04-17,2024-04-19,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-104,REF-3,2024-04-18,2024-04-20,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-105,REF-4,2024-04-19,2024-04-21,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-106,REF-5,2024-04-20,2024-04-22,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-107,REF-6,2024-04-21,2024-04-23,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-108,REF-7,2024-04-22,2024-04-24,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-109,REF-8,2024-04-23,2024-04-25,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-110,REF-9,2024-04-24,2024-04-26,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-111,REF-10,2024-04-25,2024-04-27,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-112,REF-11,2024-04-26,2024-04-28,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-113,REF-12,2024-04-27,2024-04-29,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-114,REF-13,2024-04-28,2024-04-30,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-115,REF-14,2024-04-29,2024-05-01,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-116,REF-15,2024-04-30,2024-05-02,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-117,REF-16,2024-05-01,2024-05-03,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-118,REF-17,2024-05-02,2024-05-04,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-119,REF-18,2024-05-03,2024-05-05,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-120,REF-19,2024-05-04,2024-05-06,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-121,REF-20,2024-05-05,2024-05-07,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-122,REF-21,2024-05-06,2024-05-08,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-123,REF-22,2024-05-07,2024-05-09,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-124,REF-23,2024-05-08,2024-05-10,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-125,REF-24,2024-05-09,2024-05-11,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-126,REF-25,2024-05-10,2024-05-12,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-127,REF-26,2024-05-11,2024-05-13,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-128,REF-27,2024-05-12,2024-05-14,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-129,REF-28,2024-05-13,2024-05-15,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-130,REF-29,2024-05-14,2024-05-16,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-131,REF-30,2024-05-15,2024-05-17,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-132,REF-31,2024-05-16,2024-05-18,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-133,REF-32,2024-05-17,2024-05-19,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-134,REF-33,2024-05-18,2024-05-20,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-135,REF-34,2024-05-19,2024-05-21,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-136,REF-35,2024-05-20,2024-05-22,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-137,REF-36,2024-05-21,2024-05-23,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-138,REF-37,2024-05-22,2024-05-24,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-139,REF-38,2024-05-23,2024-05-25,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-140,REF-39,2024-05-24,2024-05-26,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-141,REF-40,2024-05-25,2024-05-27,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-142,REF-41,2024-05-26,2024-05-28,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-143,REF-42,2024-05-27,2024-05-29,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-144,REF-43,2024-05-28,2024-05-30,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-145,REF-44,2024-05-29,2024-05-31,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-146,REF-45,2024-05-30,2024-06-01,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-147,REF-46,2024-05-31,2024-06-02,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-148,REF-47,2024-06-01,2024-06-03,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
B-149,REF-48,2024-06-02,2024-06-04,Harley Veum,1,Aspernatur doloremque amet quia aut.,Quia illum aut dolores.,T,Amoxicillin and Clavulanatea,100,100,Description
1 Invoice No. Reference No. Invoice Date Due Date Customer Exchange Rate Invoice Message Terms & Conditions Delivered Item Quantity Rate Description
2 B-101 REF-0 2024-04-15 2024-04-17 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
3 B-102 REF-1 2024-04-16 2024-04-18 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
4 B-103 REF-2 2024-04-17 2024-04-19 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
5 B-104 REF-3 2024-04-18 2024-04-20 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
6 B-105 REF-4 2024-04-19 2024-04-21 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
7 B-106 REF-5 2024-04-20 2024-04-22 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
8 B-107 REF-6 2024-04-21 2024-04-23 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
9 B-108 REF-7 2024-04-22 2024-04-24 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
10 B-109 REF-8 2024-04-23 2024-04-25 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
11 B-110 REF-9 2024-04-24 2024-04-26 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
12 B-111 REF-10 2024-04-25 2024-04-27 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
13 B-112 REF-11 2024-04-26 2024-04-28 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
14 B-113 REF-12 2024-04-27 2024-04-29 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
15 B-114 REF-13 2024-04-28 2024-04-30 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
16 B-115 REF-14 2024-04-29 2024-05-01 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
17 B-116 REF-15 2024-04-30 2024-05-02 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
18 B-117 REF-16 2024-05-01 2024-05-03 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
19 B-118 REF-17 2024-05-02 2024-05-04 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
20 B-119 REF-18 2024-05-03 2024-05-05 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
21 B-120 REF-19 2024-05-04 2024-05-06 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
22 B-121 REF-20 2024-05-05 2024-05-07 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
23 B-122 REF-21 2024-05-06 2024-05-08 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
24 B-123 REF-22 2024-05-07 2024-05-09 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
25 B-124 REF-23 2024-05-08 2024-05-10 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
26 B-125 REF-24 2024-05-09 2024-05-11 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
27 B-126 REF-25 2024-05-10 2024-05-12 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
28 B-127 REF-26 2024-05-11 2024-05-13 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
29 B-128 REF-27 2024-05-12 2024-05-14 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
30 B-129 REF-28 2024-05-13 2024-05-15 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
31 B-130 REF-29 2024-05-14 2024-05-16 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
32 B-131 REF-30 2024-05-15 2024-05-17 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
33 B-132 REF-31 2024-05-16 2024-05-18 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
34 B-133 REF-32 2024-05-17 2024-05-19 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
35 B-134 REF-33 2024-05-18 2024-05-20 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
36 B-135 REF-34 2024-05-19 2024-05-21 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
37 B-136 REF-35 2024-05-20 2024-05-22 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
38 B-137 REF-36 2024-05-21 2024-05-23 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
39 B-138 REF-37 2024-05-22 2024-05-24 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
40 B-139 REF-38 2024-05-23 2024-05-25 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
41 B-140 REF-39 2024-05-24 2024-05-26 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
42 B-141 REF-40 2024-05-25 2024-05-27 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
43 B-142 REF-41 2024-05-26 2024-05-28 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
44 B-143 REF-42 2024-05-27 2024-05-29 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
45 B-144 REF-43 2024-05-28 2024-05-30 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
46 B-145 REF-44 2024-05-29 2024-05-31 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
47 B-146 REF-45 2024-05-30 2024-06-01 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
48 B-147 REF-46 2024-05-31 2024-06-02 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
49 B-148 REF-47 2024-06-01 2024-06-03 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description
50 B-149 REF-48 2024-06-02 2024-06-04 Harley Veum 1 Aspernatur doloremque amet quia aut. Quia illum aut dolores. T Amoxicillin and Clavulanatea 100 100 Description

View File

@@ -0,0 +1,5 @@
First Name,Last Name,Company Name,Display Name,Email,Personal Phone Number,Work Phone Number,Website,Opening Balance,Opening Balance At,Opening Balance Ex. Rate,Currency,Active,Note,Billing Address 1,Billing Address 2,Billing Address City,Billing Address Country,Billing Address Phone,Billing Address Postcode,Billing Address State,Shipping Address 1,Shipping Address 2,Shipping Address City,Shipping Address Country,Shipping Address Phone,Shipping Address Postcode,Shipping Address State
Nicolette,Schamberger,Homenick - Hane,Rowland Rowe,cicero86@yahoo.com,811-603-2235,906-993-5190,http://google.com,54302.23,2022-02-02,2,LYD,T,Doloribus autem optio temporibus dolores mollitia sit.,862 Jessika Well,1091 Dorthy Mount,Deckowfort,Ghana,825-011-5207,38228,Oregon,37626 Thiel Villages,132 Batz Avenue,Pagacburgh,Albania,171-546-3701,13709,Georgia
Hermann,Crooks,Veum - Schaefer,Harley Veum,immanuel56@hotmail.com,449-780-9999,970-473-5785,http://google.com,54302.23,2022-02-02,2,LYD,T,Doloribus dolore dolor dicta vitae in fugit nisi quibusdam.,532 Simonis Spring,3122 Nicolas Inlet,East Matteofort,Holy See (Vatican City State),366-084-8629,41607,Montana,2889 Tremblay Plaza,71355 Kutch Isle,D'Amorehaven,Monaco,614-189-3328,09634-0435,Nevada
Nellie,Gulgowski,"Boyle, Heller and Jones",Randall Kohler,anibal_frami@yahoo.com,498-578-0740,394-550-6827,http://google.com,54302.23,2022-02-02,2,LYD,T,Vero quibusdam rem fugit aperiam est modi.,214 Sauer Villages,30687 Kacey Square,Jayceborough,Benin,332-820-1127,16425-3887,Mississippi,562 Diamond Loaf,9595 Satterfield Trafficway,Alexandrinefort,Puerto Rico,776-500-8456,30258,South Dakota
Stone,Jerde,"Cassin, Casper and Maggio",Clint McLaughlin,nathanael22@yahoo.com,562-790-6059,686-838-0027,http://google.com,54302.23,2022-02-02,2,LYD,T,Quis cumque molestias rerum.,22590 Cathy Harbor,24493 Brycen Brooks,Elnorashire,Andorra,701-852-8005,5680,Nevada,5355 Erdman Bridge,421 Jeanette Camp,East Philip,Venezuela,426-119-0858,34929-0501,Tennessee
1 First Name Last Name Company Name Display Name Email Personal Phone Number Work Phone Number Website Opening Balance Opening Balance At Opening Balance Ex. Rate Currency Active Note Billing Address 1 Billing Address 2 Billing Address City Billing Address Country Billing Address Phone Billing Address Postcode Billing Address State Shipping Address 1 Shipping Address 2 Shipping Address City Shipping Address Country Shipping Address Phone Shipping Address Postcode Shipping Address State
2 Nicolette Schamberger Homenick - Hane Rowland Rowe cicero86@yahoo.com 811-603-2235 906-993-5190 http://google.com 54302.23 2022-02-02 2 LYD T Doloribus autem optio temporibus dolores mollitia sit. 862 Jessika Well 1091 Dorthy Mount Deckowfort Ghana 825-011-5207 38228 Oregon 37626 Thiel Villages 132 Batz Avenue Pagacburgh Albania 171-546-3701 13709 Georgia
3 Hermann Crooks Veum - Schaefer Harley Veum immanuel56@hotmail.com 449-780-9999 970-473-5785 http://google.com 54302.23 2022-02-02 2 LYD T Doloribus dolore dolor dicta vitae in fugit nisi quibusdam. 532 Simonis Spring 3122 Nicolas Inlet East Matteofort Holy See (Vatican City State) 366-084-8629 41607 Montana 2889 Tremblay Plaza 71355 Kutch Isle D'Amorehaven Monaco 614-189-3328 09634-0435 Nevada
4 Nellie Gulgowski Boyle, Heller and Jones Randall Kohler anibal_frami@yahoo.com 498-578-0740 394-550-6827 http://google.com 54302.23 2022-02-02 2 LYD T Vero quibusdam rem fugit aperiam est modi. 214 Sauer Villages 30687 Kacey Square Jayceborough Benin 332-820-1127 16425-3887 Mississippi 562 Diamond Loaf 9595 Satterfield Trafficway Alexandrinefort Puerto Rico 776-500-8456 30258 South Dakota
5 Stone Jerde Cassin, Casper and Maggio Clint McLaughlin nathanael22@yahoo.com 562-790-6059 686-838-0027 http://google.com 54302.23 2022-02-02 2 LYD T Quis cumque molestias rerum. 22590 Cathy Harbor 24493 Brycen Brooks Elnorashire Andorra 701-852-8005 5680 Nevada 5355 Erdman Bridge 421 Jeanette Camp East Philip Venezuela 426-119-0858 34929-0501 Tennessee

View File

@@ -20,6 +20,7 @@ import { queryConfig } from '../hooks/query/base';
import { EnsureUserEmailVerified } from './Guards/EnsureUserEmailVerified';
import { EnsureAuthNotAuthenticated } from './Guards/EnsureAuthNotAuthenticated';
import { EnsureUserEmailNotVerified } from './Guards/EnsureUserEmailNotVerified';
import { EnsureOneClickDemoAccountEnabled } from '@/containers/OneClickDemo/EnsureOneClickDemoAccountEnabled';
const EmailConfirmation = LazyLoader({
loader: () => import('@/containers/Authentication/EmailConfirmation'),
@@ -27,7 +28,9 @@ const EmailConfirmation = LazyLoader({
const RegisterVerify = LazyLoader({
loader: () => import('@/containers/Authentication/RegisterVerify'),
});
const OneClickDemoPage = LazyLoader({
loader: () => import('@/containers/OneClickDemo/OneClickDemoPage'),
});
/**
* App inner.
*/
@@ -37,6 +40,13 @@ function AppInsider({ history }) {
<DashboardThemeProvider>
<Router history={history}>
<Switch>
<Route path={'/one_click_demo'}>
<EnsureOneClickDemoAccountEnabled>
<EnsureAuthNotAuthenticated>
<OneClickDemoPage />
</EnsureAuthNotAuthenticated>
</EnsureOneClickDemoAccountEnabled>
</Route>
<Route path={'/auth/register/verify'}>
<EnsureAuthenticated>
<EnsureUserEmailNotVerified>

View File

@@ -62,6 +62,7 @@ export function BankAccount({
balance,
loading = false,
updatedBeforeText,
uncategorizedTransactionsCount,
...restProps
}) {
return (
@@ -77,17 +78,19 @@ export function BankAccount({
</BankAccountHeader>
<BankAccountMeta>
{false && (
{uncategorizedTransactionsCount > 0 && (
<BankAccountMetaLine
title={intl.get('cash_flow.transactions_for_review')}
value={'0'}
title={intl.get('banking.transactions_for_review')}
value={uncategorizedTransactionsCount}
className={clsx({ [Classes.SKELETON]: loading })}
/>
)}
{updatedBeforeText && (
<BankAccountMetaLine
title={updatedBeforeText}
className={clsx({ [Classes.SKELETON]: loading })}
/>
)}
<BankAccountMetaLine
title={updatedBeforeText}
className={clsx({ [Classes.SKELETON]: loading })}
/>
</BankAccountMeta>
<BankAccountBalance amount={balance} loading={loading} />

View File

@@ -23,6 +23,9 @@ export function DashboardSockets() {
intent: Intent.SUCCESS,
});
});
socket.current.on('SUBSCRIPTION_CHANGED', () => {
client.invalidateQueries('GetSubscriptions');
});
return () => {
socket.current.removeAllListeners();
socket.current.close();

View File

@@ -2,7 +2,6 @@
display: flex;
flex-direction: row;
gap: 10px;
margin-bottom: 14px;
}
.tag{

View File

@@ -0,0 +1,6 @@
export const Config = {
oneClickDemo: {
enable: process.env.REACT_APP_ONE_CLICK_DEMO_ENABLE === 'true',
demoUrl: process.env.REACT_APP_DEMO_ACCOUNT_URL || '',
},
};

View File

@@ -3,30 +3,30 @@ import intl from 'react-intl-universal';
export const getAddMoneyInOptions = () => [
{
name: intl.get('cash_flow.owner_contribution'),
name: intl.get('banking.owner_contribution'),
value: 'owner_contribution',
},
{
name: intl.get('cash_flow.other_income'),
name: intl.get('banking.other_income'),
value: 'other_income',
},
{
name: intl.get('cash_flow.transfer_form_account'),
name: intl.get('banking.transfer_form_account'),
value: 'transfer_from_account',
},
];
export const getAddMoneyOutOptions = () => [
{
name: intl.get('cash_flow.owner_drawings'),
name: intl.get('banking.owner_drawings'),
value: 'OwnerDrawing',
},
{
name: intl.get('cash_flow.expenses'),
name: intl.get('banking.expenses'),
value: 'other_expense',
},
{
name: intl.get('cash_flow.transfer_to_account'),
name: intl.get('banking.transfer_to_account'),
value: 'transfer_to_account',
},
];

View File

@@ -441,12 +441,12 @@ export const SidebarMenu = [
// # Cashflow
// ---------------
{
text: <T id={'siebar.cashflow'} />,
text: <T id={'sidebar.banking'} />,
type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Cashflow,
children: [
{
text: <T id={'siebar.cashflow'} />,
text: <T id={'sidebar.banking'} />,
type: ISidebarMenuItemType.Group,
children: [
{

View File

@@ -227,7 +227,7 @@ function AccountTransactionsActionsBar({
<CashFlowMenuItems
items={addMoneyInOptions}
onItemSelect={handleMoneyInFormTransaction}
text={<T id={'cash_flow.label.add_money_in'} />}
text={<T id={'banking.label.add_money_in'} />}
buttonProps={{
icon: <Icon icon={'arrow-downward'} iconSize={20} />,
}}
@@ -235,7 +235,7 @@ function AccountTransactionsActionsBar({
<CashFlowMenuItems
items={addMoneyOutOptions}
onItemSelect={handlMoneyOutFormTransaction}
text={<T id={'cash_flow.label.add_money_out'} />}
text={<T id={'banking.label.add_money_out'} />}
buttonProps={{
icon: <Icon icon={'arrow-upward'} iconSize={20} />,
}}

View File

@@ -0,0 +1,5 @@
.dateFieldGroup{
margin-bottom: 0;
}

View File

@@ -0,0 +1,235 @@
// @ts-nocheck
import { Button, FormGroup, Intent, Position } from '@blueprintjs/core';
import * as Yup from 'yup';
import moment from 'moment';
import { Form, Formik, FormikConfig, useFormikContext } from 'formik';
import {
FDateInput,
FFormGroup,
FSelect,
Group,
Icon,
Stack,
} from '@/components';
const defaultValues = {
period: 'all_dates',
fromDate: '',
toDate: '',
};
const validationSchema = Yup.object().shape({
fromDate: Yup.date()
.nullable()
.required('From Date is required')
.max(Yup.ref('toDate'), 'From Date cannot be after To Date'),
toDate: Yup.date()
.nullable()
.required('To Date is required')
.min(Yup.ref('fromDate'), 'To Date cannot be before From Date'),
});
interface AccountTransactionsDateFilterFormValues {
period: string;
fromDate: string;
toDate: string;
}
interface UncategorizedTransactionsDateFilterProps {
initialValues?: AccountTransactionsDateFilterFormValues;
onSubmit?: FormikConfig<AccountTransactionsDateFilterFormValues>['onSubmit'];
}
export function AccountTransactionsDateFilterForm({
initialValues = {},
onSubmit,
}: UncategorizedTransactionsDateFilterProps) {
const handleSubmit = (values, bag) => {
return onSubmit && onSubmit(values, bag);
};
const formInitialValues = {
...defaultValues,
...initialValues,
};
return (
<Formik
initialValues={formInitialValues}
onSubmit={handleSubmit}
validationSchema={validationSchema}
>
<Form>
<Stack spacing={15}>
<Group spacing={10}>
<AccountTransactionDatePeriodField />
<FFormGroup
name={'fromDate'}
label={'From Date'}
style={{ marginBottom: 0, flex: '1' }}
>
<FDateInput
name={'fromDate'}
popoverProps={{ position: Position.BOTTOM, minimal: true }}
formatDate={(date) => date.toLocaleDateString()}
parseDate={(str) => new Date(str)}
inputProps={{
fill: true,
placeholder: 'MM/DD/YYY',
leftElement: <Icon icon={'date-range'} />,
}}
/>
</FFormGroup>
<FormGroup
label={'To Date'}
name={'toDate'}
style={{ marginBottom: 0, flex: '1' }}
>
<FDateInput
name={'toDate'}
popoverProps={{ position: Position.BOTTOM, minimal: true }}
formatDate={(date) => date.toLocaleDateString()}
parseDate={(str) => new Date(str)}
inputProps={{
fill: true,
placeholder: 'MM/DD/YYY',
leftElement: <Icon icon={'date-range'} />,
}}
/>
</FormGroup>
</Group>
<AccountTransactionsDateFilterFooter />
</Stack>
</Form>
</Formik>
);
}
function AccountTransactionsDateFilterFooter() {
const { submitForm, setValues } = useFormikContext();
const handleFilterBtnClick = () => {
submitForm();
};
const handleClearBtnClick = () => {
setValues({
...defaultValues,
});
submitForm();
};
return (
<Group spacing={10}>
<Button
small
intent={Intent.PRIMARY}
onClick={handleFilterBtnClick}
style={{ minWidth: 75 }}
>
Filter
</Button>
<Button
intent={Intent.DANGER}
small
onClick={handleClearBtnClick}
minimal
>
Clear
</Button>
</Group>
);
}
function AccountTransactionDatePeriodField() {
const { setFieldValue } = useFormikContext();
const handleItemChange = (item) => {
const { fromDate, toDate } = getDateRangePeriod(item.value);
setFieldValue('fromDate', fromDate);
setFieldValue('toDate', toDate);
setFieldValue('period', item.value);
};
return (
<FFormGroup
name={'period'}
label={'Date'}
style={{ marginBottom: 0, flex: '0 28%' }}
>
<FSelect
name={'period'}
items={periodOptions}
onItemSelect={handleItemChange}
popoverProps={{ captureDismiss: true }}
/>
</FFormGroup>
);
}
const periodOptions = [
{ text: 'All Dates', value: 'all_dates' },
{ text: 'Custom', value: 'custom' },
{ text: 'Today', value: 'today' },
{ text: 'Yesterday', value: 'yesterday' },
{ text: 'This week', value: 'this_week' },
{ text: 'This year', value: 'this_year' },
{ text: 'This month', value: 'this_month' },
{ text: 'last week', value: 'last_week' },
{ text: 'Last year', value: 'last_year' },
{ text: 'Last month', value: 'last_month' },
{ text: 'Last month', value: 'last_month' },
];
const getDateRangePeriod = (period: string) => {
switch (period) {
case 'today':
return {
fromDate: moment().startOf('day').toDate(),
toDate: moment().endOf('day').toDate(),
};
case 'yesterday':
return {
fromDate: moment().subtract(1, 'days').startOf('day').toDate(),
toDate: moment().subtract(1, 'days').endOf('day').toDate(),
};
case 'this_week':
return {
fromDate: moment().startOf('week').toDate(),
toDate: moment().endOf('week').toDate(),
};
case 'this_month':
return {
fromDate: moment().startOf('month').toDate(),
toDate: moment().endOf('month').toDate(),
};
case 'this_year':
return {
fromDate: moment().startOf('year').toDate(),
toDate: moment().endOf('year').toDate(),
};
case 'last_week':
return {
fromDate: moment().subtract(1, 'weeks').startOf('week').toDate(),
toDate: moment().subtract(1, 'weeks').endOf('week').toDate(),
};
case 'last_month':
return {
fromDate: moment().subtract(1, 'months').startOf('month').toDate(),
toDate: moment().subtract(1, 'months').endOf('month').toDate(),
};
case 'last_year':
return {
fromDate: moment().subtract(1, 'years').startOf('year').toDate(),
toDate: moment().subtract(1, 'years').endOf('year').toDate(),
};
case 'all_dates':
case 'custom':
default:
return { fromDate: null, toDate: null };
}
};

View File

@@ -1,10 +1,12 @@
// @ts-nocheck
import * as R from 'ramda';
import { useMemo } from 'react';
import * as R from 'ramda';
import { useAppQueryString } from '@/hooks';
import { Group } from '@/components';
import { Group, Stack, } from '@/components';
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
import { TagsControl } from '@/components/TagsControl';
import { AccountUncategorizedDateFilter } from './UncategorizedTransactions/AccountUncategorizedDateFilter';
import { Divider } from '@blueprintjs/core';
export function AccountTransactionsUncategorizeFilter() {
const { bankAccountMetaSummary } = useAccountTransactionsContext();
@@ -54,12 +56,17 @@ export function AccountTransactionsUncategorizeFilter() {
);
return (
<Group position={'apart'}>
<TagsControl
options={options}
value={locationQuery?.uncategorizedFilter || 'all'}
onValueChange={handleTabsChange}
/>
<Group position={'apart'} style={{ marginBottom: 14 }}>
<Group align={'stretch'} spacing={10}>
<TagsControl
options={options}
value={locationQuery?.uncategorizedFilter || 'all'}
onValueChange={handleTabsChange}
/>
<Divider />
<AccountUncategorizedDateFilter />
</Group>
<TagsControl
options={[{ value: 'excluded', label: 'Excluded' }]}
value={locationQuery?.uncategorizedFilter || 'all'}

View File

@@ -2,9 +2,11 @@
import React from 'react';
import { flatten, map } from 'lodash';
import * as R from 'ramda';
import { IntersectionObserver } from '@/components';
import { useAccountUncategorizedTransactionsInfinity } from '@/hooks/query';
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
import { withBanking } from '../withBanking';
const AccountUncategorizedTransactionsContext = React.createContext();
@@ -13,9 +15,15 @@ function flattenInfinityPagesData(data) {
}
/**
* Account uncategorized transctions provider.
* Account un-categorized transactions provider.
*/
function AccountUncategorizedTransactionsBoot({ children }) {
function AccountUncategorizedTransactionsBootRoot({
// #withBanking
uncategorizedTransactionsFilter,
// #ownProps
children,
}) {
const { accountId } = useAccountTransactionsContext();
// Fetches the uncategorized transactions.
@@ -29,6 +37,8 @@ function AccountUncategorizedTransactionsBoot({ children }) {
hasNextPage: hasUncategorizedTransactionsNextPage,
} = useAccountUncategorizedTransactionsInfinity(accountId, {
page_size: 50,
min_date: uncategorizedTransactionsFilter?.fromDate || null,
max_date: uncategorizedTransactionsFilter?.toDate || null,
});
// Memorized the cashflow account transactions.
const uncategorizedTransactions = React.useMemo(
@@ -69,6 +79,12 @@ function AccountUncategorizedTransactionsBoot({ children }) {
);
}
const AccountUncategorizedTransactionsBoot = R.compose(
withBanking(({ uncategorizedTransactionsFilter }) => ({
uncategorizedTransactionsFilter,
})),
)(AccountUncategorizedTransactionsBootRoot);
const useAccountUncategorizedTransactionsContext = () =>
React.useContext(AccountUncategorizedTransactionsContext);

View File

@@ -1,9 +1,11 @@
// @ts-nocheck
import React from 'react';
import { flatten, map } from 'lodash';
import * as R from 'ramda';
import { IntersectionObserver } from '@/components';
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
import { useExcludedBankTransactionsInfinity } from '@/hooks/query/bank-rules';
import { withBanking } from '../../withBanking';
interface ExcludedBankTransactionsContextValue {
isExcludedTransactionsLoading: boolean;
@@ -27,7 +29,11 @@ interface ExcludedBankTransactionsTableBootProps {
/**
* Account uncategorized transctions provider.
*/
function ExcludedBankTransactionsTableBoot({
function ExcludedBankTransactionsTableBootRoot({
// #withBanking
uncategorizedTransactionsFilter,
// #ownProps
children,
}: ExcludedBankTransactionsTableBootProps) {
const { accountId } = useAccountTransactionsContext();
@@ -44,6 +50,8 @@ function ExcludedBankTransactionsTableBoot({
} = useExcludedBankTransactionsInfinity({
page_size: 50,
account_id: accountId,
min_date: uncategorizedTransactionsFilter?.fromDate || null,
max_date: uncategorizedTransactionsFilter.toDate || null,
});
// Memorized the cashflow account transactions.
const excludedBankTransactions = React.useMemo(
@@ -84,6 +92,12 @@ function ExcludedBankTransactionsTableBoot({
);
}
const ExcludedBankTransactionsTableBoot = R.compose(
withBanking(({ uncategorizedTransactionsFilter }) => ({
uncategorizedTransactionsFilter,
})),
)(ExcludedBankTransactionsTableBootRoot);
const useExcludedTransactionsBoot = () =>
React.useContext(ExcludedTransactionsContext);

View File

@@ -37,12 +37,13 @@ export function useExcludedTransactionsColumns() {
() => [
{
Header: 'Date',
accessor: 'formatted_date',
accessor: 'formatted_date',
width: 110,
},
{
Header: 'Description',
accessor: descriptionAccessor,
textOverview: true,
},
{
Header: 'Payee',

View File

@@ -41,7 +41,7 @@ export function usePendingTransactionsTableColumns() {
},
{
id: 'deposit',
Header: intl.get('cash_flow.label.deposit'),
Header: intl.get('banking.label.deposit'),
accessor: 'formatted_deposit_amount',
width: 40,
className: 'deposit',
@@ -51,7 +51,7 @@ export function usePendingTransactionsTableColumns() {
},
{
id: 'withdrawal',
Header: intl.get('cash_flow.label.withdrawal'),
Header: intl.get('banking.label.withdrawal'),
accessor: 'formatted_withdrawal_amount',
className: 'withdrawal',
width: 40,

View File

@@ -1,9 +1,11 @@
// @ts-nocheck
import React from 'react';
import { flatten, map } from 'lodash';
import { IntersectionObserver } from '@/components';
import * as R from 'ramda';
import { IntersectionObserver, NumericInputCell } from '@/components';
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
import { useRecognizedBankTransactionsInfinity } from '@/hooks/query/bank-rules';
import { withBanking } from '../../withBanking';
interface RecognizedTransactionsContextValue {
isRecongizedTransactionsLoading: boolean;
@@ -27,7 +29,10 @@ interface RecognizedTransactionsTableBootProps {
/**
* Account uncategorized transctions provider.
*/
function RecognizedTransactionsTableBoot({
function RecognizedTransactionsTableBootRoot({
// #withBanking
uncategorizedTransactionsFilter,
children,
}: RecognizedTransactionsTableBootProps) {
const { accountId } = useAccountTransactionsContext();
@@ -44,6 +49,8 @@ function RecognizedTransactionsTableBoot({
} = useRecognizedBankTransactionsInfinity({
page_size: 50,
account_id: accountId,
min_date: uncategorizedTransactionsFilter.fromDate || null,
max_date: uncategorizedTransactionsFilter?.toDate || null,
});
// Memorized the cashflow account transactions.
const recognizedTransactions = React.useMemo(
@@ -84,6 +91,12 @@ function RecognizedTransactionsTableBoot({
);
}
const RecognizedTransactionsTableBoot = R.compose(
withBanking(({ uncategorizedTransactionsFilter }) => ({
uncategorizedTransactionsFilter,
})),
)(RecognizedTransactionsTableBootRoot);
const useRecognizedTransactionsBoot = () =>
React.useContext(RecognizedTransactionsContext);

View File

@@ -0,0 +1,105 @@
// @ts-nocheck
import { useState } from 'react';
import * as R from 'ramda';
import moment from 'moment';
import { Box, Icon } from '@/components';
import { Classes, Popover, Position } from '@blueprintjs/core';
import { withBankingActions } from '../../withBankingActions';
import { withBanking } from '../../withBanking';
import { AccountTransactionsDateFilterForm } from '../AccountTransactionsDateFilter';
import { TagButton } from './TagButton';
function AccountUncategorizedDateFilterRoot({
uncategorizedTransactionsFilter,
}) {
const fromDate = uncategorizedTransactionsFilter?.fromDate;
const toDate = uncategorizedTransactionsFilter?.toDate;
const fromDateFormatted = moment(fromDate).isSame(
moment().format('YYYY'),
'year',
)
? moment(fromDate).format('MMM, DD')
: moment(fromDate).format('MMM, DD, YYYY');
const toDateFormatted = moment(toDate).isSame(moment().format('YYYY'), 'year')
? moment(toDate).format('MMM, DD')
: moment(toDate).format('MMM, DD, YYYY');
const buttonText =
fromDate && toDate
? `Date: ${fromDateFormatted}${toDateFormatted}`
: 'Date Filter';
// Popover open state.
const [isOpen, setIsOpen] = useState<boolean>(false);
// Handle the filter form submitting.
const handleSubmit = () => {
setIsOpen(false);
};
return (
<Popover
content={
<Box style={{ padding: 18 }}>
<UncategorizedTransactionsDateFilter onSubmit={handleSubmit} />
</Box>
}
position={Position.RIGHT}
popoverClassName={Classes.POPOVER_CONTENT}
isOpen={isOpen}
onClose={() => setIsOpen(false)}
>
<TagButton
outline
icon={<Icon icon={'date-range'} />}
onClick={() => setIsOpen(!isOpen)}
>
{buttonText}
</TagButton>
</Popover>
);
}
export const AccountUncategorizedDateFilter = R.compose(
withBanking(({ uncategorizedTransactionsFilter }) => ({
uncategorizedTransactionsFilter,
})),
)(AccountUncategorizedDateFilterRoot);
export const UncategorizedTransactionsDateFilter = R.compose(
withBankingActions,
withBanking(({ uncategorizedTransactionsFilter }) => ({
uncategorizedTransactionsFilter,
})),
)(
({
// #withBankingActions
setUncategorizedTransactionsFilter,
// #withBanking
uncategorizedTransactionsFilter,
// #ownProps
onSubmit,
}) => {
const initialValues = {
...uncategorizedTransactionsFilter,
};
const handleSubmit = (values) => {
setUncategorizedTransactionsFilter({
fromDate: values.fromDate,
toDate: values.toDate,
});
onSubmit && onSubmit(values);
};
return (
<AccountTransactionsDateFilterForm
initialValues={initialValues}
onSubmit={handleSubmit}
/>
);
},
);

View File

@@ -0,0 +1,11 @@
.root{
min-height: 26px;
border-radius: 15px;
font-size: 13px;
padding: 0 10px;
&:global(.bp4-button:not([class*=bp4-intent-]):not(.bp4-minimal)) {
background: #fff;
border: 1px solid #e1e2e8;
}
}

View File

@@ -0,0 +1,9 @@
// @ts-nocheck
import { Button } from "@blueprintjs/core"
import styles from './TagButton.module.scss';
export const TagButton = (props) => {
return <Button {...props} className={styles.root} />
}

View File

@@ -121,7 +121,7 @@ export function useAccountUncategorizedTransactionsColumns() {
},
{
id: 'deposit',
Header: intl.get('cash_flow.label.deposit'),
Header: intl.get('banking.label.deposit'),
accessor: 'formatted_deposit_amount',
width: 40,
className: 'deposit',
@@ -131,7 +131,7 @@ export function useAccountUncategorizedTransactionsColumns() {
},
{
id: 'withdrawal',
Header: intl.get('cash_flow.label.withdrawal'),
Header: intl.get('banking.label.withdrawal'),
accessor: 'formatted_withdrawal_amount',
className: 'withdrawal',
width: 40,

View File

@@ -116,7 +116,7 @@ export function useAccountTransactionsColumns() {
},
{
id: 'deposit',
Header: intl.get('cash_flow.label.deposit'),
Header: intl.get('banking.label.deposit'),
accessor: 'formatted_deposit',
width: 110,
className: 'deposit',
@@ -126,7 +126,7 @@ export function useAccountTransactionsColumns() {
},
{
id: 'withdrawal',
Header: intl.get('cash_flow.label.withdrawal'),
Header: intl.get('banking.label.withdrawal'),
accessor: 'formatted_withdrawal',
className: 'withdrawal',
width: 150,
@@ -136,7 +136,7 @@ export function useAccountTransactionsColumns() {
},
{
id: 'running_balance',
Header: intl.get('cash_flow.label.running_balance'),
Header: intl.get('banking.label.running_balance'),
accessor: 'formatted_running_balance',
className: 'running_balance',
width: 150,

View File

@@ -78,13 +78,13 @@ function CashFlowAccountsActionsBar({
<Button
className={Classes.MINIMAL}
icon={<Icon icon={'plus-24'} iconSize={20} />}
text={<T id={'cash_flow.label.add_cash_account'} />}
text={<T id={'banking.label.add_cash_account'} />}
onClick={handleAddBankAccount}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon icon={'plus-24'} iconSize={20} />}
text={<T id={'cash_flow.label.add_bank_account'} />}
text={<T id={'banking.label.add_bank_account'} />}
onClick={handleAddCashAccount}
/>
<NavbarDivider />

View File

@@ -123,7 +123,12 @@ function CashflowBankAccount({
code={account.code}
balance={!isNull(account.amount) ? account.formatted_amount : '-'}
type={account.account_type}
updatedBeforeText={getUpdatedBeforeText(account.createdAt)}
updatedBeforeText={
account.last_feeds_updated_from_now
? `Updated ${account.last_feeds_updated_from_now} ago`
: ''
}
uncategorizedTransactionsCount={account.uncategorized_transactions}
/>
</CashflowAccountAnchor>
</ContextMenu2>

View File

@@ -25,6 +25,8 @@ export const withBanking = (mapState) => {
categorizedTransactionsSelected:
state.plaid.categorizedTransactionsSelected,
uncategorizedTransactionsFilter: state.plaid.uncategorizedFilter
};
return mapState ? mapState(mapped, state, props) : mapped;
};

Some files were not shown because too many files have changed in this diff Show More