Compare commits

...

10 Commits

Author SHA1 Message Date
vchikalkin
797da91b8e service: add field 'duration' 2025-05-08 17:40:15 +03:00
vchikalkin
3c2c7701b1 customer::service relations 2025-05-07 17:46:58 +03:00
vchikalkin
970c391b0f order: add field 'date' 2025-05-07 17:46:45 +03:00
vchikalkin
7b4c5e280a slot: add beforeCreate check 2025-02-20 18:05:57 +03:00
vchikalkin
e64f5453de slot: beforeUpdate check 2025-02-19 18:14:28 +03:00
vchikalkin
554fa6adc0 add type 'service' 2025-02-12 11:16:44 +03:00
vchikalkin
b30e9e46fb fix fields types & names 2025-02-11 11:40:37 +03:00
vchikalkin
efe34ba945 upgrade for slots & orders functional 2025-01-30 18:56:18 +03:00
vchikalkin
844365c40a upgrade entities 2025-01-27 19:33:49 +03:00
vchikalkin
4001b68491 customer.active=false by default 2025-01-10 19:17:56 +03:00
12 changed files with 237 additions and 45 deletions

View File

@ -12,11 +12,11 @@
},
"pluginOptions": {},
"attributes": {
"datestart": {
"datetime_start": {
"type": "datetime",
"required": true
},
"dateend": {
"datetime_end": {
"type": "datetime",
"required": true
},
@ -29,12 +29,12 @@
],
"default": "created"
},
"sessionsTotal": {
"sessions_total": {
"type": "integer",
"default": 10,
"required": true
},
"sessionsCompleted": {
"sessions_completed": {
"type": "integer",
"default": 0
},

View File

@ -35,7 +35,7 @@
},
"active": {
"type": "boolean",
"default": true,
"default": false,
"required": false
},
"clients": {
@ -68,14 +68,14 @@
"target": "api::order.order",
"mappedBy": "client"
},
"setting": {
"type": "relation",
"relation": "oneToOne",
"target": "api::setting.setting",
"mappedBy": "customer"
},
"photoUrl": {
"type": "string"
},
"services": {
"type": "relation",
"relation": "oneToMany",
"target": "api::service.service",
"mappedBy": "master"
}
}
}

View File

@ -26,15 +26,9 @@
"price": {
"type": "integer"
},
"service": {
"service_description": {
"type": "text"
},
"slot": {
"type": "relation",
"relation": "oneToOne",
"target": "api::slot.slot",
"mappedBy": "orders"
},
"client": {
"type": "relation",
"relation": "manyToOne",
@ -46,6 +40,30 @@
"relation": "manyToOne",
"target": "api::block.block",
"inversedBy": "orders"
},
"order_number": {
"type": "integer"
},
"slot": {
"type": "relation",
"relation": "manyToOne",
"target": "api::slot.slot",
"inversedBy": "orders"
},
"time_start": {
"type": "time"
},
"time_end": {
"type": "time"
},
"services": {
"type": "relation",
"relation": "manyToMany",
"target": "api::service.service",
"inversedBy": "orders"
},
"date": {
"type": "date"
}
}
}

View File

@ -0,0 +1,36 @@
{
"kind": "collectionType",
"collectionName": "services",
"info": {
"singularName": "service",
"pluralName": "services",
"displayName": "service",
"description": ""
},
"options": {
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"name": {
"type": "string"
},
"orders": {
"type": "relation",
"relation": "manyToMany",
"target": "api::order.order",
"mappedBy": "services"
},
"master": {
"type": "relation",
"relation": "manyToOne",
"target": "api::customer.customer",
"inversedBy": "services"
},
"duration": {
"type": "time",
"required": true,
"default": "01:00:00.000"
}
}
}

View File

@ -0,0 +1,7 @@
/**
* service controller
*/
import { factories } from '@strapi/strapi'
export default factories.createCoreController('api::service.service');

View File

@ -0,0 +1,7 @@
/**
* service router
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreRouter('api::service.service');

View File

@ -0,0 +1,7 @@
/**
* service service
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreService('api::service.service');

View File

@ -4,20 +4,15 @@
"info": {
"singularName": "setting",
"pluralName": "settings",
"displayName": "Setting"
"displayName": "Setting",
"description": ""
},
"options": {
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"customer": {
"type": "relation",
"relation": "oneToOne",
"target": "api::customer.customer",
"inversedBy": "setting"
},
"recordingByBlocks": {
"recording_by_blocks": {
"type": "boolean",
"default": false
}

View File

@ -0,0 +1,76 @@
const ERR_INVALID_TIME = 'Некорректное время';
const ERR_OVERLAPPING_TIME = 'Время пересекается с другими слотами';
function timeToDate(time: string) {
return new Date(`1970-01-01T${time}Z`);
}
export default {
async beforeCreate(event) {
const { data } = event.params;
const { time_start, time_end, date } = data;
if (!time_start || !time_end) {
throw new Error(ERR_INVALID_TIME);
}
if (timeToDate(time_start) >= timeToDate(time_end)) {
throw new Error(ERR_INVALID_TIME);
}
const overlappingEntities = await strapi.db
.query('api::slot.slot')
.findMany({
where: {
date,
documentId: { $ne: data.documentId },
time_start: { $lt: time_end },
time_end: { $gt: time_start },
},
});
if (overlappingEntities.length > 0) {
throw new Error(ERR_OVERLAPPING_TIME);
}
},
async beforeUpdate(event) {
const { data, where } = event.params;
const { id: entityId } = where;
const { time_start, time_end } = data;
if (!time_start || !time_end) {
throw new Error(ERR_INVALID_TIME);
}
if (timeToDate(time_start) >= timeToDate(time_end)) {
throw new Error(ERR_INVALID_TIME);
}
const existingEntity = await strapi.db.query('api::slot.slot').findOne({
where: { id: entityId },
select: ['date', 'documentId'],
});
if (!existingEntity) {
throw new Error('Запись не найдена');
}
const { date, documentId } = existingEntity;
const overlappingEntities = await strapi.db
.query('api::slot.slot')
.findMany({
where: {
date,
id: { $ne: entityId },
documentId: { $ne: documentId },
time_start: { $lt: time_end },
time_end: { $gt: time_start },
},
});
if (overlappingEntities.length > 0) {
throw new Error(ERR_OVERLAPPING_TIME);
}
},
};

View File

@ -12,12 +12,12 @@
},
"pluginOptions": {},
"attributes": {
"datestart": {
"type": "datetime",
"time_start": {
"type": "time",
"required": true
},
"dateend": {
"type": "datetime",
"time_end": {
"type": "time",
"required": true
},
"state": {
@ -30,15 +30,18 @@
},
"orders": {
"type": "relation",
"relation": "oneToOne",
"relation": "oneToMany",
"target": "api::order.order",
"inversedBy": "slot"
"mappedBy": "slot"
},
"master": {
"type": "relation",
"relation": "manyToOne",
"target": "api::customer.customer",
"inversedBy": "slots"
},
"date": {
"type": "date"
}
}
}

1
start.cmd Normal file
View File

@ -0,0 +1 @@
pnpm develop

View File

@ -385,16 +385,17 @@ export interface ApiBlockBlock extends Struct.CollectionTypeSchema {
createdAt: Schema.Attribute.DateTime;
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private;
dateend: Schema.Attribute.DateTime & Schema.Attribute.Required;
datestart: Schema.Attribute.DateTime & Schema.Attribute.Required;
datetime_end: Schema.Attribute.DateTime & Schema.Attribute.Required;
datetime_start: Schema.Attribute.DateTime & Schema.Attribute.Required;
locale: Schema.Attribute.String & Schema.Attribute.Private;
localizations: Schema.Attribute.Relation<'oneToMany', 'api::block.block'> &
Schema.Attribute.Private;
master: Schema.Attribute.Relation<'manyToOne', 'api::customer.customer'>;
orders: Schema.Attribute.Relation<'oneToMany', 'api::order.order'>;
publishedAt: Schema.Attribute.DateTime;
sessionsCompleted: Schema.Attribute.Integer & Schema.Attribute.DefaultTo<0>;
sessionsTotal: Schema.Attribute.Integer &
sessions_completed: Schema.Attribute.Integer &
Schema.Attribute.DefaultTo<0>;
sessions_total: Schema.Attribute.Integer &
Schema.Attribute.Required &
Schema.Attribute.DefaultTo<10>;
state: Schema.Attribute.Enumeration<['created', 'paid', 'deleted']> &
@ -417,7 +418,7 @@ export interface ApiCustomerCustomer extends Struct.CollectionTypeSchema {
draftAndPublish: true;
};
attributes: {
active: Schema.Attribute.Boolean & Schema.Attribute.DefaultTo<true>;
active: Schema.Attribute.Boolean & Schema.Attribute.DefaultTo<false>;
blocks: Schema.Attribute.Relation<'oneToMany', 'api::block.block'>;
clients: Schema.Attribute.Relation<'manyToMany', 'api::customer.customer'>;
createdAt: Schema.Attribute.DateTime;
@ -439,7 +440,7 @@ export interface ApiCustomerCustomer extends Struct.CollectionTypeSchema {
publishedAt: Schema.Attribute.DateTime;
role: Schema.Attribute.Enumeration<['client', 'master']> &
Schema.Attribute.Required;
setting: Schema.Attribute.Relation<'oneToOne', 'api::setting.setting'>;
services: Schema.Attribute.Relation<'oneToMany', 'api::service.service'>;
slots: Schema.Attribute.Relation<'oneToMany', 'api::slot.slot'>;
telegramId: Schema.Attribute.BigInteger & Schema.Attribute.Unique;
updatedAt: Schema.Attribute.DateTime;
@ -465,17 +466,56 @@ export interface ApiOrderOrder extends Struct.CollectionTypeSchema {
createdAt: Schema.Attribute.DateTime;
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private;
date: Schema.Attribute.Date;
locale: Schema.Attribute.String & Schema.Attribute.Private;
localizations: Schema.Attribute.Relation<'oneToMany', 'api::order.order'> &
Schema.Attribute.Private;
order_number: Schema.Attribute.Integer;
price: Schema.Attribute.Integer;
publishedAt: Schema.Attribute.DateTime;
service: Schema.Attribute.Text;
slot: Schema.Attribute.Relation<'oneToOne', 'api::slot.slot'>;
service_description: Schema.Attribute.Text;
services: Schema.Attribute.Relation<'manyToMany', 'api::service.service'>;
slot: Schema.Attribute.Relation<'manyToOne', 'api::slot.slot'>;
state: Schema.Attribute.Enumeration<
['created', 'scheduled', 'approved', 'completed', 'cancelled']
> &
Schema.Attribute.DefaultTo<'created'>;
time_end: Schema.Attribute.Time;
time_start: Schema.Attribute.Time;
updatedAt: Schema.Attribute.DateTime;
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private;
};
}
export interface ApiServiceService extends Struct.CollectionTypeSchema {
collectionName: 'services';
info: {
description: '';
displayName: 'service';
pluralName: 'services';
singularName: 'service';
};
options: {
draftAndPublish: true;
};
attributes: {
createdAt: Schema.Attribute.DateTime;
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private;
duration: Schema.Attribute.Time &
Schema.Attribute.Required &
Schema.Attribute.DefaultTo<'01:00:00.000'>;
locale: Schema.Attribute.String & Schema.Attribute.Private;
localizations: Schema.Attribute.Relation<
'oneToMany',
'api::service.service'
> &
Schema.Attribute.Private;
master: Schema.Attribute.Relation<'manyToOne', 'api::customer.customer'>;
name: Schema.Attribute.String;
orders: Schema.Attribute.Relation<'manyToMany', 'api::order.order'>;
publishedAt: Schema.Attribute.DateTime;
updatedAt: Schema.Attribute.DateTime;
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private;
@ -485,6 +525,7 @@ export interface ApiOrderOrder extends Struct.CollectionTypeSchema {
export interface ApiSettingSetting extends Struct.CollectionTypeSchema {
collectionName: 'settings';
info: {
description: '';
displayName: 'Setting';
pluralName: 'settings';
singularName: 'setting';
@ -496,7 +537,6 @@ export interface ApiSettingSetting extends Struct.CollectionTypeSchema {
createdAt: Schema.Attribute.DateTime;
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private;
customer: Schema.Attribute.Relation<'oneToOne', 'api::customer.customer'>;
locale: Schema.Attribute.String & Schema.Attribute.Private;
localizations: Schema.Attribute.Relation<
'oneToMany',
@ -504,7 +544,7 @@ export interface ApiSettingSetting extends Struct.CollectionTypeSchema {
> &
Schema.Attribute.Private;
publishedAt: Schema.Attribute.DateTime;
recordingByBlocks: Schema.Attribute.Boolean &
recording_by_blocks: Schema.Attribute.Boolean &
Schema.Attribute.DefaultTo<false>;
updatedAt: Schema.Attribute.DateTime;
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
@ -527,15 +567,16 @@ export interface ApiSlotSlot extends Struct.CollectionTypeSchema {
createdAt: Schema.Attribute.DateTime;
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private;
dateend: Schema.Attribute.DateTime & Schema.Attribute.Required;
datestart: Schema.Attribute.DateTime & Schema.Attribute.Required;
date: Schema.Attribute.Date;
locale: Schema.Attribute.String & Schema.Attribute.Private;
localizations: Schema.Attribute.Relation<'oneToMany', 'api::slot.slot'> &
Schema.Attribute.Private;
master: Schema.Attribute.Relation<'manyToOne', 'api::customer.customer'>;
orders: Schema.Attribute.Relation<'oneToOne', 'api::order.order'>;
orders: Schema.Attribute.Relation<'oneToMany', 'api::order.order'>;
publishedAt: Schema.Attribute.DateTime;
state: Schema.Attribute.Enumeration<['open', 'reserved', 'closed']>;
time_end: Schema.Attribute.Time & Schema.Attribute.Required;
time_start: Schema.Attribute.Time & Schema.Attribute.Required;
updatedAt: Schema.Attribute.DateTime;
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &
Schema.Attribute.Private;
@ -1054,6 +1095,7 @@ declare module '@strapi/strapi' {
'api::block.block': ApiBlockBlock;
'api::customer.customer': ApiCustomerCustomer;
'api::order.order': ApiOrderOrder;
'api::service.service': ApiServiceService;
'api::setting.setting': ApiSettingSetting;
'api::slot.slot': ApiSlotSlot;
'plugin::content-releases.release': PluginContentReleasesRelease;