From 16adb65def4ef195d7f60e841761029d7dc58c8c Mon Sep 17 00:00:00 2001 From: Alexander Naydenov Date: Thu, 8 Feb 2024 13:19:48 +0500 Subject: [PATCH] feat(condo): DOMA-8359 add field `type` to `MarketPriceScope` model (#4356) --- apps/condo/domains/marketplace/constants.js | 14 ++++++ apps/condo/domains/marketplace/gql.js | 2 +- .../marketplace/schema/MarketPriceScope.js | 28 ++++++++++-- .../schema/MarketPriceScope.test.js | 25 ++++++++++- ...249-0364_marketpricescope_type_and_more.js | 44 +++++++++++++++++++ apps/condo/schema.graphql | 41 +++++++++++++++++ apps/condo/schema.ts | 39 ++++++++++++++++ 7 files changed, 187 insertions(+), 6 deletions(-) create mode 100644 apps/condo/migrations/20240205113249-0364_marketpricescope_type_and_more.js diff --git a/apps/condo/domains/marketplace/constants.js b/apps/condo/domains/marketplace/constants.js index 9347b9b5ec5..e81bc65a28c 100644 --- a/apps/condo/domains/marketplace/constants.js +++ b/apps/condo/domains/marketplace/constants.js @@ -76,6 +76,16 @@ const DEFAULT_INVOICE_CURRENCY_CODE = 'RUB' const MIN_PRICE_VALUE = 10 +const MARKETPLACE_PRICE_SCOPE_TYPE_UNKNOWN = 'unknown' +const MARKETPLACE_PRICE_SCOPE_TYPE_ORGANIZATION = 'organization' +const MARKETPLACE_PRICE_SCOPE_TYPE_PROPERTY = 'property' + +const MARKETPLACE_PRICE_SCOPES_TYPES = [ + MARKETPLACE_PRICE_SCOPE_TYPE_UNKNOWN, + MARKETPLACE_PRICE_SCOPE_TYPE_ORGANIZATION, + MARKETPLACE_PRICE_SCOPE_TYPE_PROPERTY, +] + module.exports = { ERROR_FORBID_UPDATE_TICKET, ERROR_CLIENT_DATA_DOES_NOT_MATCH_TICKET, @@ -122,4 +132,8 @@ module.exports = { ERROR_NO_FINISHED_ACQUIRING_CONTEXT, DEFAULT_INVOICE_CURRENCY_CODE, MIN_PRICE_VALUE, + MARKETPLACE_PRICE_SCOPES_TYPES, + MARKETPLACE_PRICE_SCOPE_TYPE_UNKNOWN, + MARKETPLACE_PRICE_SCOPE_TYPE_ORGANIZATION, + MARKETPLACE_PRICE_SCOPE_TYPE_PROPERTY, } diff --git a/apps/condo/domains/marketplace/gql.js b/apps/condo/domains/marketplace/gql.js index bdd555dec73..f00748c683e 100644 --- a/apps/condo/domains/marketplace/gql.js +++ b/apps/condo/domains/marketplace/gql.js @@ -26,7 +26,7 @@ const MarketItemFile = generateGqlQueries('MarketItemFile', MARKET_ITEM_FILE_FIE const MARKET_ITEM_PRICE_FIELDS = `{ price { type name price isMin vatPercent salesTaxPercent currencyCode } marketItem { id } ${COMMON_FIELDS} }` const MarketItemPrice = generateGqlQueries('MarketItemPrice', MARKET_ITEM_PRICE_FIELDS) -const MARKET_PRICE_SCOPE_FIELDS = `{ marketItemPrice { id marketItem { id name sku organization { id } marketCategory { id name order parentCategory { id order name } } } price { type name price isMin vatPercent salesTaxPercent currencyCode } } property { id addressMeta { ${ADDRESS_META_SUBFIELDS_TABLE_LIST} } } ${COMMON_FIELDS} }` +const MARKET_PRICE_SCOPE_FIELDS = `{ marketItemPrice { id marketItem { id name sku organization { id } marketCategory { id name order parentCategory { id order name } } } price { type name price isMin vatPercent salesTaxPercent currencyCode } } property { id addressMeta { ${ADDRESS_META_SUBFIELDS_TABLE_LIST} } } type ${COMMON_FIELDS} }` const MarketPriceScope = generateGqlQueries('MarketPriceScope', MARKET_PRICE_SCOPE_FIELDS) /* AUTOGENERATE MARKER */ diff --git a/apps/condo/domains/marketplace/schema/MarketPriceScope.js b/apps/condo/domains/marketplace/schema/MarketPriceScope.js index 2e8c9529818..e61f63031e3 100644 --- a/apps/condo/domains/marketplace/schema/MarketPriceScope.js +++ b/apps/condo/domains/marketplace/schema/MarketPriceScope.js @@ -9,10 +9,14 @@ const { historical, versioned, uuided, tracked, softDeleted, dvAndSender } = req const { GQLListSchema } = require('@open-condo/keystone/schema') const access = require('@condo/domains/marketplace/access/MarketPriceScope') +const { + MARKETPLACE_PRICE_SCOPES_TYPES, + MARKETPLACE_PRICE_SCOPE_TYPE_ORGANIZATION, + MARKETPLACE_PRICE_SCOPE_TYPE_PROPERTY, +} = require('@condo/domains/marketplace/constants') const { MarketItemPrice, MarketItem } = require('@condo/domains/marketplace/utils/serverSchema') const { Property } = require('@condo/domains/property/utils/serverSchema') - const ERRORS = { ORGANIZATION_IN_PROPERTY_AND_MARKET_ITEM_PRICE_NOT_MATCHED: { code: BAD_USER_INPUT, @@ -22,11 +26,9 @@ const ERRORS = { }, } - const MarketPriceScope = new GQLListSchema('MarketPriceScope', { schemaDoc: 'Which residents can see the particular market item price instance', fields: { - marketItemPrice: { schemaDoc: 'Link to market item price', type: 'Relationship', @@ -35,14 +37,32 @@ const MarketPriceScope = new GQLListSchema('MarketPriceScope', { knexOptions: { isNotNullable: true }, // Required relationship only! kmigratorOptions: { null: false, on_delete: 'models.CASCADE' }, }, - property: { schemaDoc: 'Link to property', type: 'Relationship', ref: 'Property', kmigratorOptions: { null: true, on_delete: 'models.CASCADE' }, }, + type: { + schemaDoc: 'The scope type. This is an auto-calculated field. Used to find items by scopes filled with some set of attributes.', + type: 'Select', + options: MARKETPLACE_PRICE_SCOPES_TYPES, + isRequired: true, + access: { + read: true, + create: false, + update: false, + }, + hooks: { + resolveInput: async ({ operation, resolvedData, fieldPath }) => { + if (operation === 'create') { + return resolvedData.property ? MARKETPLACE_PRICE_SCOPE_TYPE_PROPERTY : MARKETPLACE_PRICE_SCOPE_TYPE_ORGANIZATION + } + return resolvedData[fieldPath] + }, + }, + }, }, kmigratorOptions: { constraints: [ diff --git a/apps/condo/domains/marketplace/schema/MarketPriceScope.test.js b/apps/condo/domains/marketplace/schema/MarketPriceScope.test.js index ed786d36049..0ca24f6c983 100644 --- a/apps/condo/domains/marketplace/schema/MarketPriceScope.test.js +++ b/apps/condo/domains/marketplace/schema/MarketPriceScope.test.js @@ -4,7 +4,15 @@ const { faker } = require('@faker-js/faker') -const { makeLoggedInAdminClient, makeClient, UUID_RE, expectValuesOfCommonFields, expectToThrowUniqueConstraintViolationError, expectToThrowGQLError, expectToThrowAccessDeniedErrorToObjects } = require('@open-condo/keystone/test.utils') +const { + makeLoggedInAdminClient, + makeClient, + UUID_RE, + expectValuesOfCommonFields, + expectToThrowUniqueConstraintViolationError, + expectToThrowGQLError, + expectToThrowAccessDeniedErrorToObjects, +} = require('@open-condo/keystone/test.utils') const { expectToThrowAuthenticationErrorToObj, expectToThrowAuthenticationErrorToObjects, expectToThrowAccessDeniedErrorToObj, @@ -520,4 +528,19 @@ describe('MarketPriceScope', () => { }) }) }) + + describe('Scope type tests', () => { + test('type must equals "property" for scope with property', async () => { + const [property] = await createTestProperty(admin, organization) + const [obj] = await createTestMarketPriceScope(admin, price, property) + expect(obj.type).toBe('property') + }) + + test('type must equals "organization" for scope without property', async () => { + const [property] = await createTestProperty(admin, organization) + const [price] = await createTestMarketItemPrice(admin, marketItem) + const [obj] = await createTestMarketPriceScope(admin, price, property, { property: null }) + expect(obj.type).toBe('organization') + }) + }) }) diff --git a/apps/condo/migrations/20240205113249-0364_marketpricescope_type_and_more.js b/apps/condo/migrations/20240205113249-0364_marketpricescope_type_and_more.js new file mode 100644 index 00000000000..9497882ed13 --- /dev/null +++ b/apps/condo/migrations/20240205113249-0364_marketpricescope_type_and_more.js @@ -0,0 +1,44 @@ +// auto generated by kmigrator +// KMIGRATOR:0364_marketpricescope_type_and_more:IyBHZW5lcmF0ZWQgYnkgRGphbmdvIDQuMi40IG9uIDIwMjQtMDItMDUgMDY6MzMKCmZyb20gZGphbmdvLmRiIGltcG9ydCBtaWdyYXRpb25zLCBtb2RlbHMKCgpjbGFzcyBNaWdyYXRpb24obWlncmF0aW9ucy5NaWdyYXRpb24pOgoKICAgIGRlcGVuZGVuY2llcyA9IFsKICAgICAgICAoJ19kamFuZ29fc2NoZW1hJywgJzAzNjNfYXV0b18yMDI0MDEyOV8wNTI4JyksCiAgICBdCgogICAgb3BlcmF0aW9ucyA9IFsKICAgICAgICBtaWdyYXRpb25zLkFkZEZpZWxkKAogICAgICAgICAgICBtb2RlbF9uYW1lPSdtYXJrZXRwcmljZXNjb3BlJywKICAgICAgICAgICAgbmFtZT0ndHlwZScsCiAgICAgICAgICAgIGZpZWxkPW1vZGVscy5DaGFyRmllbGQoY2hvaWNlcz1bKCd1bmtub3duJywgJ3Vua25vd24nKSwgKCdvcmdhbml6YXRpb24nLCAnb3JnYW5pemF0aW9uJyksICgncHJvcGVydHknLCAncHJvcGVydHknKV0sIGRlZmF1bHQ9J3Vua25vd24nLCBtYXhfbGVuZ3RoPTUwKSwKICAgICAgICAgICAgcHJlc2VydmVfZGVmYXVsdD1GYWxzZSwKICAgICAgICApLAogICAgICAgIG1pZ3JhdGlvbnMuQWRkRmllbGQoCiAgICAgICAgICAgIG1vZGVsX25hbWU9J21hcmtldHByaWNlc2NvcGVoaXN0b3J5cmVjb3JkJywKICAgICAgICAgICAgbmFtZT0ndHlwZScsCiAgICAgICAgICAgIGZpZWxkPW1vZGVscy5UZXh0RmllbGQoYmxhbms9VHJ1ZSwgbnVsbD1UcnVlKSwKICAgICAgICApLAogICAgXQo= + +exports.up = async (knex) => { + await knex.raw(` + BEGIN; +-- +-- Add field type to marketpricescope +-- +ALTER TABLE "MarketPriceScope" ADD COLUMN "type" varchar(50) DEFAULT 'unknown' NOT NULL; +ALTER TABLE "MarketPriceScope" ALTER COLUMN "type" DROP DEFAULT; +-- +-- Add field type to marketpricescopehistoryrecord +-- +ALTER TABLE "MarketPriceScopeHistoryRecord" ADD COLUMN "type" text NULL; + +--- MANUAL +--- Set type for existing scopes +SET statement_timeout = '1500s'; +UPDATE "MarketPriceScope" SET "type"='organization' WHERE property IS NULL; +UPDATE "MarketPriceScope" SET "type"='property' WHERE property IS NOT NULL; +SET statement_timeout = '10s'; +--- LAUNAM + +COMMIT; + + `) +} + +exports.down = async (knex) => { + await knex.raw(` + BEGIN; +-- +-- Add field type to marketpricescopehistoryrecord +-- +ALTER TABLE "MarketPriceScopeHistoryRecord" DROP COLUMN "type" CASCADE; +-- +-- Add field type to marketpricescope +-- +ALTER TABLE "MarketPriceScope" DROP COLUMN "type" CASCADE; +COMMIT; + + `) +} diff --git a/apps/condo/schema.graphql b/apps/condo/schema.graphql index ef7191ae589..af67028006f 100644 --- a/apps/condo/schema.graphql +++ b/apps/condo/schema.graphql @@ -69578,6 +69578,7 @@ type MarketPriceScopeHistoryRecord { _label_: String marketItemPrice: String property: String + type: String id: ID! v: Int createdAt: String @@ -69604,6 +69605,24 @@ input MarketPriceScopeHistoryRecordWhereInput { property_not: String property_in: [String] property_not_in: [String] + type: String + type_not: String + type_contains: String + type_not_contains: String + type_starts_with: String + type_not_starts_with: String + type_ends_with: String + type_not_ends_with: String + type_i: String + type_not_i: String + type_contains_i: String + type_not_contains_i: String + type_starts_with_i: String + type_not_starts_with_i: String + type_ends_with_i: String + type_not_ends_with_i: String + type_in: [String] + type_not_in: [String] id: ID id_not: ID id_in: [ID] @@ -69687,6 +69706,8 @@ input MarketPriceScopeHistoryRecordWhereUniqueInput { } enum SortMarketPriceScopeHistoryRecordsBy { + type_ASC + type_DESC id_ASC id_DESC v_ASC @@ -69708,6 +69729,7 @@ enum SortMarketPriceScopeHistoryRecordsBy { input MarketPriceScopeHistoryRecordUpdateInput { marketItemPrice: String property: String + type: String v: Int createdAt: String updatedAt: String @@ -69730,6 +69752,7 @@ input MarketPriceScopeHistoryRecordsUpdateInput { input MarketPriceScopeHistoryRecordCreateInput { marketItemPrice: String property: String + type: String v: Int createdAt: String updatedAt: String @@ -69755,6 +69778,12 @@ input MarketItemPriceRelateToOneInput { disconnectAll: Boolean } +enum MarketPriceScopeTypeType { + unknown + organization + property +} + """ Which residents can see the particular market item price instance """ type MarketPriceScope { """ @@ -69771,6 +69800,10 @@ type MarketPriceScope { """ Link to property """ property: Property + + """ The scope type. This is an auto-calculated field. Used to find items by scopes filled with some set of attributes. + """ + type: MarketPriceScopeTypeType id: ID! v: Int createdAt: String @@ -69801,6 +69834,10 @@ input MarketPriceScopeWhereInput { marketItemPrice_is_null: Boolean property: PropertyWhereInput property_is_null: Boolean + type: MarketPriceScopeTypeType + type_not: MarketPriceScopeTypeType + type_in: [MarketPriceScopeTypeType] + type_not_in: [MarketPriceScopeTypeType] id: ID id_not: ID id_in: [ID] @@ -69868,6 +69905,8 @@ enum SortMarketPriceScopesBy { marketItemPrice_DESC property_ASC property_DESC + type_ASC + type_DESC id_ASC id_DESC v_ASC @@ -69889,6 +69928,7 @@ enum SortMarketPriceScopesBy { input MarketPriceScopeUpdateInput { marketItemPrice: MarketItemPriceRelateToOneInput property: PropertyRelateToOneInput + type: MarketPriceScopeTypeType v: Int createdAt: String updatedAt: String @@ -69908,6 +69948,7 @@ input MarketPriceScopesUpdateInput { input MarketPriceScopeCreateInput { marketItemPrice: MarketItemPriceRelateToOneInput property: PropertyRelateToOneInput + type: MarketPriceScopeTypeType v: Int createdAt: String updatedAt: String diff --git a/apps/condo/schema.ts b/apps/condo/schema.ts index 1188e777ce5..55df40ca676 100644 --- a/apps/condo/schema.ts +++ b/apps/condo/schema.ts @@ -27724,6 +27724,8 @@ export type MarketPriceScope = { marketItemPrice?: Maybe; /** Link to property */ property?: Maybe; + /** The scope type. This is an auto-calculated field. Used to find items by scopes filled with some set of attributes. */ + type?: Maybe; id: Scalars['ID']; v?: Maybe; createdAt?: Maybe; @@ -27743,6 +27745,7 @@ export type MarketPriceScope = { export type MarketPriceScopeCreateInput = { marketItemPrice?: Maybe; property?: Maybe; + type?: Maybe; v?: Maybe; createdAt?: Maybe; updatedAt?: Maybe; @@ -27767,6 +27770,7 @@ export type MarketPriceScopeHistoryRecord = { _label_?: Maybe; marketItemPrice?: Maybe; property?: Maybe; + type?: Maybe; id: Scalars['ID']; v?: Maybe; createdAt?: Maybe; @@ -27785,6 +27789,7 @@ export type MarketPriceScopeHistoryRecord = { export type MarketPriceScopeHistoryRecordCreateInput = { marketItemPrice?: Maybe; property?: Maybe; + type?: Maybe; v?: Maybe; createdAt?: Maybe; updatedAt?: Maybe; @@ -27808,6 +27813,7 @@ export enum MarketPriceScopeHistoryRecordHistoryActionType { export type MarketPriceScopeHistoryRecordUpdateInput = { marketItemPrice?: Maybe; property?: Maybe; + type?: Maybe; v?: Maybe; createdAt?: Maybe; updatedAt?: Maybe; @@ -27833,6 +27839,24 @@ export type MarketPriceScopeHistoryRecordWhereInput = { property_not?: Maybe; property_in?: Maybe>>; property_not_in?: Maybe>>; + type?: Maybe; + type_not?: Maybe; + type_contains?: Maybe; + type_not_contains?: Maybe; + type_starts_with?: Maybe; + type_not_starts_with?: Maybe; + type_ends_with?: Maybe; + type_not_ends_with?: Maybe; + type_i?: Maybe; + type_not_i?: Maybe; + type_contains_i?: Maybe; + type_not_contains_i?: Maybe; + type_starts_with_i?: Maybe; + type_not_starts_with_i?: Maybe; + type_ends_with_i?: Maybe; + type_not_ends_with_i?: Maybe; + type_in?: Maybe>>; + type_not_in?: Maybe>>; id?: Maybe; id_not?: Maybe; id_in?: Maybe>>; @@ -27924,9 +27948,16 @@ export type MarketPriceScopeHistoryRecordsUpdateInput = { data?: Maybe; }; +export enum MarketPriceScopeTypeType { + Unknown = 'unknown', + Organization = 'organization', + Property = 'property' +} + export type MarketPriceScopeUpdateInput = { marketItemPrice?: Maybe; property?: Maybe; + type?: Maybe; v?: Maybe; createdAt?: Maybe; updatedAt?: Maybe; @@ -27945,6 +27976,10 @@ export type MarketPriceScopeWhereInput = { marketItemPrice_is_null?: Maybe; property?: Maybe; property_is_null?: Maybe; + type?: Maybe; + type_not?: Maybe; + type_in?: Maybe>>; + type_not_in?: Maybe>>; id?: Maybe; id_not?: Maybe; id_in?: Maybe>>; @@ -75325,6 +75360,8 @@ export enum SortMarketItemsBy { } export enum SortMarketPriceScopeHistoryRecordsBy { + TypeAsc = 'type_ASC', + TypeDesc = 'type_DESC', IdAsc = 'id_ASC', IdDesc = 'id_DESC', VAsc = 'v_ASC', @@ -75348,6 +75385,8 @@ export enum SortMarketPriceScopesBy { MarketItemPriceDesc = 'marketItemPrice_DESC', PropertyAsc = 'property_ASC', PropertyDesc = 'property_DESC', + TypeAsc = 'type_ASC', + TypeDesc = 'type_DESC', IdAsc = 'id_ASC', IdDesc = 'id_DESC', VAsc = 'v_ASC',