Skip to content

Commit

Permalink
chore(condo): Fix marketplace measures logic (#5776)
Browse files Browse the repository at this point in the history
* fix(condo): improve invoice form service selection and price measure handling

* feat(condo): if resident creates invoice, infer price measure from market item

* fix(condo): revert debug changes in BaseInvoiceForm

* fix(condo): fix linter issues

* fix(condo): fix test request

* fix(condo): fix difference

* fix(condo): fix difference
  • Loading branch information
toplenboren authored Feb 6, 2025
1 parent f36f47d commit f083a46
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,31 +73,31 @@ const PLUS_BUTTON_STYLE: CSSProperties = {
}

const ServiceFormItem = styled(Form.Item)`
& .ant-form-item-label {
padding-bottom: 8px;
& > .ant-form-item-no-colon {
height: 22px;
}
& .ant-form-item-label {
padding-bottom: 8px;
& > .ant-form-item-no-colon {
height: 22px;
}
}
`
const FormItemWithCustomWarningColor = styled(ServiceFormItem)`
.ant-input-status-warning {
&:focus {
box-shadow: 0 0 0 1px ${colors.red[5]} !important;
}
border-color: ${colors.red[5]} !important;;
.ant-input-status-warning {
&:focus {
box-shadow: 0 0 0 1px ${colors.red[5]} !important;
}
.ant-input-group-wrapper-status-warning .ant-input-group-addon {
color: ${colors.red[5]};
border-color: ${colors.red[5]};
}
.ant-form-item-explain-warning {
color: ${colors.red[5]};
}
border-color: ${colors.red[5]} !important;;
}
.ant-input-group-wrapper-status-warning .ant-input-group-addon {
color: ${colors.red[5]};
border-color: ${colors.red[5]};
}
.ant-form-item-explain-warning {
color: ${colors.red[5]};
}
`

const SubTotalInfo = ({ label, total, large = false, totalTextType }) => {
Expand Down Expand Up @@ -663,6 +663,12 @@ const ServicesList = ({ organizationId, propertyId, form, currencySymbol, disabl
>
<Select
defaultValue={PriceMeasuresType.PerItem}
onSelect={newPriceMeasure => {
updateRowFields(marketItemForm.name, {
measure: newPriceMeasure,
...(newPriceMeasure === null && { count: 1 }),
})
}}
>
<Select.Option
key={PriceMeasuresType.PerItem}
Expand All @@ -683,8 +689,8 @@ const ServicesList = ({ organizationId, propertyId, form, currencySymbol, disabl
{ PerMeterPriceMeasureLabel }
</Select.Option>
<Select.Option
key={undefined}
value={undefined}
key='NoValue'
value={null}
>
{ NoPriceMeasureLabel }
</Select.Option>
Expand All @@ -707,7 +713,7 @@ const ServicesList = ({ organizationId, propertyId, form, currencySymbol, disabl
validator: (_, value) => {
if (
new RegExp(`^${FromMessage} (\\d+|\\d+(,|.)\\d+)$`).test(value) ||
value === ContractPriceMessage
value === ContractPriceMessage
) {
form.setFieldsValue({
hasIsMinPrice: true,
Expand All @@ -732,7 +738,7 @@ const ServicesList = ({ organizationId, propertyId, form, currencySymbol, disabl
validator: (_, value) => {
if (
new RegExp(`^(${FromMessage} |)(\\d+|\\d+(,|.)\\d+)$`).test(value) ||
value === ContractPriceMessage
value === ContractPriceMessage
) {
return Promise.resolve()
}
Expand Down Expand Up @@ -764,7 +770,7 @@ const ServicesList = ({ organizationId, propertyId, form, currencySymbol, disabl

const splittedValue = value.split(' ')
const isMin = (splittedValue.length === 2 && splittedValue[0] === FromMessage) ||
(splittedValue.length === 1 && splittedValue[0] === ContractPriceMessage)
(splittedValue.length === 1 && splittedValue[0] === ContractPriceMessage)

updateRowFields(marketItemForm.name, {
isMin,
Expand All @@ -782,9 +788,10 @@ const ServicesList = ({ organizationId, propertyId, form, currencySymbol, disabl
labelCol={{ span: 24 }}
rules={[requiredValidator]}
initialValue={1}
shouldUpdate
>
<Select
disabled={disabled}
disabled={disabled || form.getFieldValue(['rows', marketItemForm.name, 'measure']) === null}
options={[...Array(50).keys() ].map( i => ({
label: `${i + 1}`,
key: i + 1,
Expand Down Expand Up @@ -1340,4 +1347,4 @@ export const BaseInvoiceForm: React.FC<BaseInvoiceFormProps> = (props) => {
</>
)}/>
)
}
}
54 changes: 54 additions & 0 deletions apps/condo/domains/marketplace/schema/Invoice.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ const {
makeClientWithStaffUser, createTestPhone,
} = require('@condo/domains/user/utils/testSchema')

const { PRICE_MEASURES } = require('./fields/price')


dayjs.extend(isSameOrAfter)

Expand Down Expand Up @@ -887,6 +889,58 @@ describe('Invoice', () => {
})
})
})

describe('rows.*.measure', () => {
test('invoice.rows.*.measure is inferred from MarketItemPrice when set as resident', async () => {
const [o10n] = await createTestOrganization(adminClient)

await createTestAcquiringIntegrationContext(adminClient, o10n, dummyAcquiringIntegration, {
invoiceStatus: CONTEXT_FINISHED_STATUS,
invoiceRecipient: createTestRecipient(),
})

const [property] = await createTestProperty(adminClient, o10n)

const residentClient = await makeClientWithResidentUser()
const unitType = FLAT_UNIT_TYPE
const unitName = faker.lorem.word()
const [resident] = await registerResidentByTestClient(
residentClient,
{
address: property.address,
addressMeta: property.addressMeta,
unitType,
unitName,
})

const [parentCategory] = await createTestMarketCategory(adminClient)
const [marketCategory] = await createTestMarketCategory(adminClient, {
parentCategory: { connect: { id: parentCategory.id } },
})
const [marketItem] = await createTestMarketItem(adminClient, marketCategory, o10n)
const [itemPrice] = await createTestMarketItemPrice(adminClient, marketItem, { price: { type: 'variant', name: 'Installation of AC unit', price: '80', isMin: false, vatPercent: '11', currencyCode: 'USD', measure: PRICE_MEASURES.PER_ITEM } })
const [priceScope] = await createTestMarketPriceScope(adminClient, itemPrice, property)

await registerResidentInvoiceByTestClient(
residentClient,
pick(resident, 'id'),
[{
priceScope: pick(priceScope, 'id'),
count: 3,
}],
)

const invoices = await Invoice.getAll(residentClient, {})
expect(invoices).toHaveLength(1)

const [invoice] = invoices
expect(invoice.rows).toEqual([
expect.objectContaining({
measure: PRICE_MEASURES.PER_ITEM,
}),
])
})
})
})
})

Expand Down
2 changes: 0 additions & 2 deletions apps/condo/domains/marketplace/schema/MarketItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const { MarketItemPrice } = require('@condo/domains/marketplace/utils/serverSche
const MarketItem = new GQLListSchema('MarketItem', {
schemaDoc: 'Information about the market product',
fields: {

name: {
schemaDoc: 'Name of market item',
type: 'Text',
Expand Down Expand Up @@ -48,7 +47,6 @@ const MarketItem = new GQLListSchema('MarketItem', {
knexOptions: { isNotNullable: true }, // Required relationship only!
kmigratorOptions: { null: false, on_delete: 'models.CASCADE' },
},

},
hooks: {
afterChange: async ({ context, operation, originalInput, existingItem }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const { makeClientWithResidentUser } = require('@condo/domains/user/utils/testSc

const ajv = new Ajv()
const validatePriceField = ajv.compile(PRICE_FIELD_SCHEMA)
const validPriceFieldValue = [{ type: 'variant', name: 'name', price: '300', isMin: false, vatPercent: '20', salesTaxPercent: '0', currencyCode: 'RUB', measure: PRICE_MEASURES.PerItem }]
const validPriceFieldValue = [{ type: 'variant', name: 'name', price: '300', isMin: false, vatPercent: '20', salesTaxPercent: '0', currencyCode: 'RUB', measure: PRICE_MEASURES.PER_ITEM }]

describe('MarketItemPrice', () => {
let admin, organization, marketCategory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ const RegisterResidentInvoiceService = new GQLCustomSchema('RegisterResidentInvo
const priceScopes = await MarketPriceScope.getAll(
context,
{ deletedAt: null, id_in: priceScopesIds },
'id marketItemPrice { price { vatPercent salesTaxPercent price isMin } ' +
'id marketItemPrice { price { vatPercent measure salesTaxPercent price isMin } ' +
'marketItem { name sku organization { id } } }'
)

Expand All @@ -130,16 +130,25 @@ const RegisterResidentInvoiceService = new GQLCustomSchema('RegisterResidentInvo

const hasMinPrice = priceScopes.some((priceScope) => get(priceScope, ['marketItemPrice', 'price', 0, 'isMin'], false))

const rows = priceScopes.map((priceScope) => ({
name: get(priceScope, ['marketItemPrice', 'marketItem', 'name']),
toPay: get(priceScope, ['marketItemPrice', 'price', 0, 'price']),
isMin: get(priceScope, ['marketItemPrice', 'price', 0, 'isMin']),
count: get(priceScopesCounts, get(priceScope, 'id'), 0),
currencyCode: DEFAULT_INVOICE_CURRENCY_CODE,
vatPercent: get(priceScope, ['marketItemPrice', 'price', 0, 'vatPercent'], get(acquiringContext, 'invoiceVatPercent')) || '',
salesTaxPercent: get(priceScope, ['marketItemPrice', 'price', 0, 'salesTaxPercent'], get(acquiringContext, 'invoiceSalesTaxPercent')) || '',
sku: get(priceScope, ['marketItemPrice', 'marketItem', 'sku']),
}))
const rows = priceScopes.map((priceScope) => {
const result = {
name: get(priceScope, ['marketItemPrice', 'marketItem', 'name']),
toPay: get(priceScope, ['marketItemPrice', 'price', 0, 'price']),
isMin: get(priceScope, ['marketItemPrice', 'price', 0, 'isMin']),
count: get(priceScopesCounts, get(priceScope, 'id'), 0),
currencyCode: DEFAULT_INVOICE_CURRENCY_CODE,
vatPercent: get(priceScope, ['marketItemPrice', 'price', 0, 'vatPercent'], get(acquiringContext, 'invoiceVatPercent')) || '',
salesTaxPercent: get(priceScope, ['marketItemPrice', 'price', 0, 'salesTaxPercent'], get(acquiringContext, 'invoiceSalesTaxPercent')) || '',
sku: get(priceScope, ['marketItemPrice', 'marketItem', 'sku']),
}

const measureFromMarketItem = get(priceScope, ['marketItemPrice', 'price', 0, 'measure'])
if (measureFromMarketItem) {
result.measure = measureFromMarketItem
}

return result
})

if (rows.length === 0) {
throw new GQLError(ERRORS.EMPTY_ROWS, context)
Expand Down

0 comments on commit f083a46

Please sign in to comment.