Skip to content

Commit

Permalink
Revert "feat(condo): INFRA-463 resolve N+1 issues for AllResidentBill… (
Browse files Browse the repository at this point in the history
#5220)

* Revert "feat(condo): INFRA-463 resolve N+1 issues for AllResidentBillingReceipts model (#5161)"

This reverts commit e263530.

* fix(condo): revert
  • Loading branch information
dkoviazin authored Sep 11, 2024
1 parent f1001b3 commit 4de9253
Show file tree
Hide file tree
Showing 9 changed files with 26 additions and 355 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -197,17 +197,12 @@ const compactDistributionSettings = (settings = []) => {


const getAcquiringIntegrationContextFormula = async (context, acquiringContextId) => {
const acquiringContext = await AcquiringIntegrationContextApi.getOne(context, { id: acquiringContextId })
return getAcquiringIntegrationContextFormulaByInstance(acquiringContext)
}

const getAcquiringIntegrationContextFormulaByInstance = (acquiringContext) => {
let {
integration: {
explicitFeeDistributionSchema: acquiringDistributionSchema,
},
implicitFeeDistributionSchema: contextDistributionSchema,
} = acquiringContext
} = await AcquiringIntegrationContextApi.getOne(context, { id: acquiringContextId })
if (!Array.isArray(acquiringDistributionSchema)) {
acquiringDistributionSchema = []
}
Expand All @@ -220,6 +215,5 @@ const getAcquiringIntegrationContextFormulaByInstance = (acquiringContext) => {
module.exports = {
FeeDistribution,
getAcquiringIntegrationContextFormula,
getAcquiringIntegrationContextFormulaByInstance,
compactDistributionSettings,
}
7 changes: 0 additions & 7 deletions apps/condo/domains/billing/gql.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,6 @@ const BillingReceiptAdmin = generateGqlQueries('BillingReceipt', BILLING_RECEIPT
const RESIDENT_BILLING_RECEIPTS_FIELDS = `{ id ${BILLING_RECEIPT_RECIPIENT_FIELDS} period toPay paid toPayDetails { ${BILLING_RECEIPT_TO_PAY_DETAILS_FIELDS} } ${BILLING_RECEIPT_SERVICE_FIELDS} printableNumber serviceConsumer { id paymentCategory } currencyCode category { id name } isPayable file { file { id originalFilename publicUrl mimetype } controlSum } }`
const ResidentBillingReceipt = generateGqlQueries('ResidentBillingReceipt', RESIDENT_BILLING_RECEIPTS_FIELDS)

/**
* AllResidentBillingReceiptService queries
*/
const RESIDENT_BILLING_RECEIPT_ADMIN_FIELDS = `{ id dv category ${BILLING_CATEGORY_FIELDS} ${BILLING_RECEIPT_RECIPIENT_FIELDS} receiver { id tin iec bic bankAccount isApproved } account { id number unitType unitName fullName property { address } ownerType globalId isClosed } period toPay toPayDetails { ${BILLING_RECEIPT_TO_PAY_DETAILS_FIELDS} } ${BILLING_RECEIPT_SERVICE_FIELDS} printableNumber context ${BILLING_INTEGRATION_ORGANIZATION_CONTEXT_FIELDS} file { id sensitiveDataFile { id filename originalFilename publicUrl mimetype } publicDataFile { id filename originalFilename publicUrl mimetype } controlSum } }`
const ResidentBillingReceiptAdmin = generateGqlQueries('BillingReceipt', RESIDENT_BILLING_RECEIPT_ADMIN_FIELDS)

const RESIDENT_BILLING_VIRTUAL_RECEIPTS_FIELDS = `{ id ${BILLING_RECEIPT_RECIPIENT_FIELDS} period toPay explicitFee paid ${BILLING_RECEIPT_SERVICE_FIELDS} printableNumber serviceConsumer { id paymentCategory } currencyCode category { id name } isPayable }`
const ResidentBillingVirtualReceipt = generateGqlQueries('ResidentBillingVirtualReceipt', RESIDENT_BILLING_VIRTUAL_RECEIPTS_FIELDS)

Expand Down Expand Up @@ -125,7 +119,6 @@ module.exports = {
BillingReceiptForOrganization,
BillingReceiptAdmin,
ResidentBillingReceipt,
ResidentBillingReceiptAdmin,
ResidentBillingVirtualReceipt,
RESIDENT_BILLING_RECEIPTS_FIELDS,
BillingRecipient,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,25 @@
*/

const Big = require('big.js')
const { pick, get, isNil, min } = require('lodash')
const { pick, get, isNil } = require('lodash')

const { generateQuerySortBy } = require('@open-condo/codegen/generate.gql')
const { generateQueryWhereInput } = require('@open-condo/codegen/generate.gql')
const FileAdapter = require('@open-condo/keystone/fileAdapter/fileAdapter')
const { GQLCustomSchema, find } = require('@open-condo/keystone/schema')

const { PAYMENT_DONE_STATUS, PAYMENT_WITHDRAWN_STATUS } = require('@condo/domains/acquiring/constants/payment')
const { AcquiringIntegrationContext } = require('@condo/domains/acquiring/utils/serverSchema')
const {
getAcquiringIntegrationContextFormulaByInstance,
FeeDistribution,
} = require('@condo/domains/acquiring/utils/serverSchema/feeDistribution')
const { getAcquiringIntegrationContextFormula, FeeDistribution } = require('@condo/domains/acquiring/utils/serverSchema/feeDistribution')
const access = require('@condo/domains/billing/access/AllResidentBillingReceipts')
const { BILLING_RECEIPT_FILE_FOLDER_NAME } = require('@condo/domains/billing/constants/constants')
const { BillingReceiptAdmin, getPaymentsSum } = require('@condo/domains/billing/utils/serverSchema')
const { normalizeUnitName } = require('@condo/domains/billing/utils/unitName.utils')
const { Contact } = require('@condo/domains/contact/utils/serverSchema')

const {
BILLING_RECEIPT_RECIPIENT_FIELD_NAME,
BILLING_RECEIPT_TO_PAY_DETAILS_FIELD_NAME,
BILLING_RECEIPT_SERVICES_FIELD,
} = require('@condo/domains/billing/constants/constants')
const {
ResidentBillingReceiptAdmin,
getPaymentsSumByPayments,
} = require('@condo/domains/billing/utils/serverSchema')
const { normalizeUnitName } = require('@condo/domains/billing/utils/unitName.utils')
const { Contact } = require('@condo/domains/contact/utils/serverSchema')

} = require('../constants/constants')

const Adapter = new FileAdapter(BILLING_RECEIPT_FILE_FOLDER_NAME)

Expand All @@ -47,7 +39,7 @@ const getFile = (receipt, contacts) => {
}
const accountUnitName = get(receipt, ['account', 'unitName'])
const accountUnitType = get(receipt, ['account', 'unitType'])
const propertyAddress = get(receipt, ['account', 'property', 'address'])
const propertyAddress = get(receipt, ['property', 'address'])

// let's search for a contact
// if any exists = user allowed to see sensitive data
Expand Down Expand Up @@ -145,7 +137,7 @@ const AllResidentBillingReceiptsService = new GQLCustomSchema('AllResidentBillin
'OR': receiptsQuery,
}

const receiptsForConsumer = await ResidentBillingReceiptAdmin.getAll(
const receiptsForConsumer = await BillingReceiptAdmin.getAll(
context,
joinedReceiptsQuery,
{
Expand All @@ -162,33 +154,8 @@ const AllResidentBillingReceiptsService = new GQLCustomSchema('AllResidentBillin
deletedAt: null,
})

// cache billing receipt for calculation of is payable field
const minPeriod = min(receiptsForConsumer.map(item => item.period))
const nextPeriodBillingReceiptsCache = await find('BillingReceipt', {
account: { id_in: [...new Set(receiptsForConsumer.map(item => item.account.id))], deletedAt: null },
OR: [
{ receiver: { AND: [{ id_in: [...new Set(receiptsForConsumer.map(item => item.account.id))] }, { deletedAt: null } ] } },
{ category: { AND: [{ id_in: [...new Set(receiptsForConsumer.map(item => item.category.id))] }, { deletedAt: null } ] } },
],
period_gt: minPeriod,
deletedAt: null,
})

// cache acquiring integration contexts
const aicIds = serviceConsumersWithBillingAccount.map(consumer => consumer.acquiringIntegrationContext)
.filter(aic => !isNil(aic))
const acquiringContexts = await AcquiringIntegrationContext.getAll(context, {
id_in: aicIds,
})

receiptsForConsumer.forEach(receipt => {
const file = getFile(receipt, contacts)
const isPayable = nextPeriodBillingReceiptsCache.filter(item => {
return receipt.account.id === item.account && (
receipt.category.id === item.category ||
receipt.receiver.id === item.receiver
) && receipt.period < item.period
}).length === 0
processedReceipts.push({
id: receipt.id,
dv: receipt.dv,
Expand All @@ -206,18 +173,10 @@ const AllResidentBillingReceiptsService = new GQLCustomSchema('AllResidentBillin
get(receipt, ['context', 'organization', 'id']) === organization ),
currencyCode: get(receipt, ['context', 'integration', 'currencyCode'], null),
file,
isPayable,
isPayable: receipt.isPayable,
})
})

// cache already paid payments
const paymentsCache = await find('Payment', {
organization: { id_in: [... new Set(processedReceipts.map(item => get(item, ['serviceConsumer', 'organization'])))] },
accountNumber_in: [... new Set(processedReceipts.map(item => get(item, ['serviceConsumer', 'accountNumber'])))],
period: minPeriod,
status_in: [PAYMENT_DONE_STATUS, PAYMENT_WITHDRAWN_STATUS],
})

//
// Set receipt.paid field and calculate fees
//
Expand All @@ -226,20 +185,19 @@ const AllResidentBillingReceiptsService = new GQLCustomSchema('AllResidentBillin
const organizationId = get(receipt.serviceConsumer, ['organization'])
const accountNumber = get(receipt.serviceConsumer, ['accountNumber'])
const billingCategory = get(receipt, ['category']) || {}
const alreadyPaidPayments = paymentsCache.filter(payment => {
return payment.organization === organizationId
&& payment.accountNumber === accountNumber
&& payment.period === get(receipt, 'period', null)
&& payment.recipientBic === get(receipt, ['recipient', 'bic'], null)
&& payment.recipientBankAccount === get(receipt, ['recipient', 'bankAccount'], null)
})
const paid = await getPaymentsSumByPayments(alreadyPaidPayments)
const paid = await getPaymentsSum(
context,
organizationId,
accountNumber,
get(receipt, 'period', null),
get(receipt, ['recipient', 'bic'], null),
get(receipt, ['recipient', 'bankAccount'], null)
)
const acquiringContextId = get(receipt, ['serviceConsumer', 'acquiringIntegrationContext'], null)
const toPay = get(receipt, ['toPay'], 0)
let fee = '0'
if (acquiringContextId) {
const acquiringContext = acquiringContexts.find(item => item.id === acquiringContextId) || {}
const formula = getAcquiringIntegrationContextFormulaByInstance(acquiringContext)
const formula = await getAcquiringIntegrationContextFormula(context, acquiringContextId)
const feeCalculator = new FeeDistribution(formula, billingCategory.id)
const { explicitFee } = feeCalculator.calculate(Big(toPay).minus(Big(paid)).toFixed(2))
fee = String(explicitFee)
Expand All @@ -258,4 +216,4 @@ const AllResidentBillingReceiptsService = new GQLCustomSchema('AllResidentBillin

module.exports = {
AllResidentBillingReceiptsService,
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/**
* Generated by `createservice billing.BillingReceiptsService --type queries`
*/

const { basename } = require('path')

const { faker } = require('@faker-js/faker')
const Big = require('big.js')
const dayjs = require('dayjs')

const { ResidentBillingReceipt, PUBLIC_FILE, PRIVATE_FILE } = require('@condo/domains/billing/utils/testSchema')
const {
Expand Down Expand Up @@ -350,42 +350,4 @@ describe('AllResidentBillingReceiptsService', () => {
})
})

describe('Is payable logics', () => {
test('Should mark as not payable since has newest receipt for the same category', async () => {
const accountNumber = faker.random.alphaNumeric(12)
const address = utils.createAddressWithUnit()
const [thisMonth] = dayjs().format('MM-YYYY').split('-').map(Number)
const [prevMonth] = dayjs().add(-1, 'month').format('MM-YYYY').split('-').map(Number)
const [[{ id: housingReceiptId1 }, { id: housingReceiptId2 }]] = await utils.createReceipts([
utils.createJSONReceipt({ month: prevMonth, accountNumber, address, category: { id: HOUSING_CATEGORY } }),
utils.createJSONReceipt({ month: thisMonth, accountNumber, address, category: { id: HOUSING_CATEGORY } }),
])

const resident = await utils.createResident()
await utils.createServiceConsumer(resident, accountNumber)

const receipts = await ResidentBillingReceipt.getAll(utils.clients.resident)
expect(receipts.some(({ id, isPayable }) => id === housingReceiptId1 && !isPayable)).toBeTruthy()
expect(receipts.some(({ id, isPayable }) => id === housingReceiptId2 && isPayable)).toBeTruthy()
})
test('Should mark as not payable since has newest receipt for the same receiver', async () => {
const accountNumber = faker.random.alphaNumeric(12)
const address = utils.createAddressWithUnit()
const recipient = utils.createRecipient()
const [thisMonth] = dayjs().format('MM-YYYY').split('-').map(Number)
const [prevMonth] = dayjs().add(-1, 'month').format('MM-YYYY').split('-').map(Number)
const [[{ id: receiptId1 }, { id: receiptId2 }]] = await utils.createReceipts([
utils.createJSONReceipt({ month: prevMonth, accountNumber, address, ...recipient }),
utils.createJSONReceipt({ month: thisMonth, accountNumber, address, ...recipient }),
])

const resident = await utils.createResident()
await utils.createServiceConsumer(resident, accountNumber)

const receipts = await ResidentBillingReceipt.getAll(utils.clients.resident)
expect(receipts.some(({ id, isPayable }) => id === receiptId1 && !isPayable)).toBeTruthy()
expect(receipts.some(({ id, isPayable }) => id === receiptId2 && isPayable)).toBeTruthy()
})
})

})
8 changes: 0 additions & 8 deletions apps/condo/domains/billing/utils/serverSchema/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const { BillingAccount: BillingAccountGQL } = require('@condo/domains/billing/gq
const { BillingReceipt: BillingReceiptGQL } = require('@condo/domains/billing/gql')
const { BillingReceiptAdmin: BillingReceiptAdminGQL } = require('@condo/domains/billing/gql')
const { ResidentBillingReceipt: ResidentBillingReceiptGQL } = require('@condo/domains/billing/gql')
const { ResidentBillingReceiptAdmin: ResidentBillingReceiptAdminGQL } = require('@condo/domains/billing/gql')
const { ResidentBillingVirtualReceipt: ResidentBillingVirtualReceiptGQL } = require('@condo/domains/billing/gql')
const { BillingRecipient: BillingRecipientGQL } = require('@condo/domains/billing/gql')
const { BillingCategory: BillingCategoryGQL } = require('@condo/domains/billing/gql')
Expand All @@ -42,7 +41,6 @@ const BillingAccount = generateServerUtils(BillingAccountGQL)
const BillingReceipt = generateServerUtils(BillingReceiptGQL)
const BillingReceiptAdmin = generateServerUtils(BillingReceiptAdminGQL)
const ResidentBillingReceipt = generateServerUtils(ResidentBillingReceiptGQL)
const ResidentBillingReceiptAdmin = generateServerUtils(ResidentBillingReceiptAdminGQL)
const ResidentBillingVirtualReceipt = generateServerUtils(ResidentBillingVirtualReceiptGQL)
const BillingRecipient = generateServerUtils(BillingRecipientGQL)
const BillingCategory = generateServerUtils(BillingCategoryGQL)
Expand Down Expand Up @@ -80,10 +78,6 @@ const getPaymentsSum = async (context, organizationId, accountNumber, period, bi
recipientBic: bic,
recipientBankAccount: bankAccount,
})
return getPaymentsSumByPayments(payments)
}

const getPaymentsSumByPayments = (payments) => {
return payments.reduce((total, current) => (Big(total).plus(current.amount)), 0).toFixed(8).toString()
}

Expand Down Expand Up @@ -169,13 +163,11 @@ module.exports = {
BillingReceipt,
BillingReceiptAdmin,
ResidentBillingReceipt,
ResidentBillingReceiptAdmin,
ResidentBillingVirtualReceipt,
BillingRecipient,
BillingCategory,
registerBillingReceipts,
getPaymentsSum,
getPaymentsSumByPayments,
sendNewReceiptMessagesToResidentScopes,
BillingReceiptFile,
validateQRCode,
Expand Down
6 changes: 1 addition & 5 deletions apps/condo/k6/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ docker pull grafana/k6:master-with-browser
## Native package

```bash
export BASE_URL=http://localhost:3000
export [email protected]
export AUTH_PASSWORD=secret_example

yarn --cwd . webpack && k6 run <path to script in dist directory>
BASE_URL=http://localhost:3000 [email protected] AUTH_PASSWORD=secret_example k6 run <path to script>
```

## Docker image
Expand Down
Loading

0 comments on commit 4de9253

Please sign in to comment.