Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(condo): DOMA-10042 handler for suggesting providers #5163

Merged
merged 10 commits into from
Sep 5, 2024
Merged
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const {
createTestOrganization,
updateTestOrganization,
createTestOrganizationEmployeeRole,
createTestOrganizationEmployee,
} = require('@condo/domains/organization/utils/testSchema')
Expand All @@ -21,6 +22,11 @@ const OrganizationTestMixin = {
await createTestOrganizationEmployee(this.clients.admin, this.organization, this.clients.employee[type].user, role)
},

async updateOrganization (updateInput) {
const [updatedOrganization] = await updateTestOrganization(this.clients.admin, this.organization.id, updateInput)
dkoviazin marked this conversation as resolved.
Show resolved Hide resolved
this.organization = updatedOrganization
}

}

module.exports = {
Expand Down
3 changes: 2 additions & 1 deletion apps/condo/domains/organization/constants/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ const DEFAULT_ROLES = {
},
}



module.exports = {
TIN_LENGTH,
DEFAULT_ORGANIZATION_TIMEZONE,
Expand All @@ -445,5 +447,4 @@ module.exports = {
MIN_ROLE_NAME_LENGTH,
MAX_ROLE_NAME_LENGTH,
MAX_ROLE_DESCRIPTION_LENGTH,
MAX_ROLE_COUNT,
}
1 change: 1 addition & 0 deletions apps/condo/domains/organization/utils/testSchema/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ async function replaceOrganizationEmployeeRoleByTestClient(client, organization,
throwIfError(data, errors)
return [data.result, attrs]
}

/* AUTOGENERATE MARKER <FACTORY> */

module.exports = {
Expand Down
1 change: 1 addition & 0 deletions apps/condo/domains/organization/utils/tin.utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const isValidTin = (tinValue = null, country = RUSSIA_COUNTRY) => {

const getIsValidTin = (country = RUSSIA_COUNTRY) => (tinValue = null) => isValidTin(tinValue, country)


module.exports = {
validateTinRU,
isValidTin,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Generated by `createservice organization.SuggestServiceProviderService --type queries`
*/
const { throwAuthenticationError } = require('@open-condo/keystone/apolloErrorFormatter')

const { RESIDENT } = require('@condo/domains/user/constants/common')

async function canSuggestServiceProvider ({ authentication: { item: user } }) {
if (!user) return throwAuthenticationError()
if (user.deletedAt) return false
return user.isAdmin || user.isSupport || user.type === RESIDENT
}

/*
Rules are logical functions that used for list access, and may return a boolean (meaning
all or no items are available) or a set of filters that limit the available items.
*/
module.exports = {
canSuggestServiceProvider,
}
7 changes: 7 additions & 0 deletions apps/condo/domains/resident/constants/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ const MAX_RESIDENT_DISCOVER_CONSUMERS_BY_WINDOW_SEC = 10
const RESIDENT_FIND_ORGANIZATIONS_WINDOW_SEC = 24 * 60 * 60 // seconds
const MAX_RESIDENT_FIND_ORGANIZATIONS_BY_WINDOW_SEC = 100

const RESIDENT_SUGGEST_SERVICE_PROVIDER_WINDOW_IN_SEC = 24 * 60 * 60 // 1 day in seconds
const MAX_RESIDENT_SUGGEST_SERVICE_PROVIDER_CALLS_BY_WINDOW_SEC = 100
const MAX_SUGGEST_SERVICE_PROVIDER_ITEMS_COUNT = 20

const REDIS_LAST_DATE_KEY = 'LAST_SEND_BILLING_RECEIPT_NOTIFICATION_CREATED_AT'

module.exports = {
Expand All @@ -177,4 +181,7 @@ module.exports = {
RESIDENT_FIND_ORGANIZATIONS_WINDOW_SEC,
MAX_RESIDENT_FIND_ORGANIZATIONS_BY_WINDOW_SEC,
REDIS_LAST_DATE_KEY,
RESIDENT_SUGGEST_SERVICE_PROVIDER_WINDOW_IN_SEC,
MAX_RESIDENT_SUGGEST_SERVICE_PROVIDER_CALLS_BY_WINDOW_SEC,
MAX_SUGGEST_SERVICE_PROVIDER_ITEMS_COUNT,
}
7 changes: 7 additions & 0 deletions apps/condo/domains/resident/gql.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ const REGISTER_RESIDENT_SERVICE_CONSUMERS_MUTATION = gql`
}
`

const SUGGEST_SERVICE_PROVIDER_QUERY = gql`
query suggestServiceProvider($data: SuggestServiceProviderInput!) {
result: suggestServiceProvider(data: $data) { tin name }
}
`

module.exports = {
Resident,
REGISTER_RESIDENT_MUTATION,
Expand All @@ -87,5 +93,6 @@ module.exports = {
REGISTER_RESIDENT_SERVICE_CONSUMERS_MUTATION,
REGISTER_RESIDENT_INVOICE_MUTATION,
FIND_ORGANIZATIONS_FOR_ADDRESS_QUERY,
SUGGEST_SERVICE_PROVIDER_QUERY,
/* AUTOGENERATE MARKER <EXPORTS> */
}
102 changes: 102 additions & 0 deletions apps/condo/domains/resident/schema/SuggestServiceProviderService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Generated by `createservice organization.SuggestServiceProviderService --type queries`
*/

const { pick, uniqBy } = require('lodash')

const { GQLCustomSchema, itemsQuery, find } = require('@open-condo/keystone/schema')

const { CONTEXT_FINISHED_STATUS } = require('@condo/domains/acquiring/constants/context')
const { SERVICE_PROVIDER_TYPE } = require('@condo/domains/organization/constants/common')
const access = require('@condo/domains/resident/access/SuggestServiceProviderService')
const {
MAX_RESIDENT_SUGGEST_SERVICE_PROVIDER_CALLS_BY_WINDOW_SEC,
RESIDENT_SUGGEST_SERVICE_PROVIDER_WINDOW_IN_SEC,
MAX_SUGGEST_SERVICE_PROVIDER_ITEMS_COUNT,
} = require('@condo/domains/resident/constants')
const { RESIDENT } = require('@condo/domains/user/constants/common')
const { RedisGuard } = require('@condo/domains/user/utils/serverSchema/guards')

const redisGuard = new RedisGuard()

const checkLimits = async (uniqueField) => {
YEgorLu marked this conversation as resolved.
Show resolved Hide resolved
await redisGuard.checkCustomLimitCounters(
`suggest-service-provider-by-tin-${uniqueField}`,
SavelevMatthew marked this conversation as resolved.
Show resolved Hide resolved
dkoviazin marked this conversation as resolved.
Show resolved Hide resolved
YEgorLu marked this conversation as resolved.
Show resolved Hide resolved
RESIDENT_SUGGEST_SERVICE_PROVIDER_WINDOW_IN_SEC,
MAX_RESIDENT_SUGGEST_SERVICE_PROVIDER_CALLS_BY_WINDOW_SEC,
)
}

const filterOrganizationsByAcquiringContextOrMeterResourceOwnership = async (context, organizations) => {
const organizationIds = [...new Set(organizations.map(organization => organization.id))]

const acquiringIntegrationContexts = await find('AcquiringIntegrationContext', {
organization: { id_in: organizationIds },
deletedAt: null,
status: CONTEXT_FINISHED_STATUS,
})

const meterResourceOwners = await find('MeterResourceOwner', {
organization: { id_in: organizationIds },
deletedAt: null,
})

const organizationsForSuggest = new Set(
acquiringIntegrationContexts.map(context => context.organization)
.concat(meterResourceOwners.map(owner => owner.organization))
)

return organizations.filter(organization => organizationsForSuggest.has(organization.id))
}


const SuggestServiceProviderService = new GQLCustomSchema('SuggestServiceProviderService', {
types: [
{
access: true,
type: 'input SuggestServiceProviderInput { search: String! }',
},
{
access: true,
type: 'type SuggestServiceProviderOutput { tin: String!, name: String! }',
},
],

queries: [
{
access: access.canSuggestServiceProvider,
schema: 'suggestServiceProvider (data: SuggestServiceProviderInput!): [SuggestServiceProviderOutput]',
resolver: async (parent, args, context = {}) => {
if (context.authedItem.type === RESIDENT) {
await checkLimits(context.authedItem.id)
}

const { data: { search } } = args
if (!search || search.length < 3) {
return []
}

const serviceProviders = await itemsQuery('Organization', {
where: {
OR: [
{ tin_starts_with: search.trim() },
{ name_contains_i: search.trim() },
],
deletedAt: null,
type: SERVICE_PROVIDER_TYPE,
},
first: MAX_SUGGEST_SERVICE_PROVIDER_ITEMS_COUNT,
})

const serviceProvidersForSuggest = await filterOrganizationsByAcquiringContextOrMeterResourceOwnership(context, serviceProviders)
return uniqBy(serviceProvidersForSuggest, 'tin')
.map(serviceProvider => pick(serviceProvider, ['tin', 'name']))
},
},
],

})

module.exports = {
SuggestServiceProviderService,
}
Loading
Loading