Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import * as Sequelize from 'sequelize'
- import { BaseModel, SequelizeModels } from './modelTypes'
- import {Moment} from "moment";
- import * as moment from 'moment'
- import { LocationGI } from './location'
- import { SurveyGI} from './survey'
- import { ServiceOptionGI } from './serviceOption'
- import { ServiceCategoryGI } from './serviceCategory'
- import { ResourceTypeGI } from './resourceType'
- import { PriceRuleGI } from './priceRule'
- import { ServiceResourceTypeLinkGA } from './serviceResourceTypeLink'
- import { ResourceGI } from './resource'
- import { ServiceResourceLinkGA } from './serviceResourceLink'
- import { NotificationTypeGI } from './notificationType'
- import { BookingOptionGI } from './bookingOption'
- import db from './index'
- import { Availability } from '../lib/availability'
- import { IAvailabilityConfig } from '../lib/availability/types'
- import { getI18nTitle, localizationMixin, i18nUpdate } from '../lib/i18n'
- import { PriceNotFound } from '../lib/errors/entities/service'
- export interface ServiceGA extends BaseModel{
- name? : string;
- deletedAt?: Moment;
- type?: ServiceTypeEnum;
- working_hours?: string;
- non_available_schedule?: string;
- min_duration?: number;
- max_duration?: number;
- default_duration?: number;
- time_gap?: number;
- min_booking_interval?: number;
- max_booking_interval?: number;
- check_in_time?: number;
- check_out_time?: number;
- NotificationTypes?: NotificationTypeGI[];
- location_id?: number;
- Survey?: SurveyGI;
- ServiceOptions?: ServiceOptionGI[];
- ServiceCategories?: ServiceCategoryGI[];
- ResourceTypes?: ResourceTypeGI[];
- Resources?: ResourceGI[];
- BookingOptions?: BookingOptionGI[];
- slot_duration?: number;
- cancel_gap?: number;
- PriceRules?: PriceRuleGI[];
- availability?: object;
- price?: number;
- Locations?: LocationGI[];
- }
- export enum ServiceTypeEnum {
- type1,
- type2
- }
- export interface ServiceGI extends Sequelize.Instance<ServiceGA>, ServiceGA {
- getLocations: Sequelize.BelongsToManyGetAssociationsMixin<LocationGI>;
- setLocations: Sequelize.BelongsToManySetAssociationsMixin<LocationGI, number, 'membership_location_link'>;
- getSurvey: Sequelize.BelongsToGetAssociationMixin<SurveyGI>;
- setSurvey: Sequelize.BelongsToSetAssociationMixin<SurveyGI, number>;
- getServiceOptions: Sequelize.HasManyGetAssociationsMixin<ServiceOptionGI>;
- setServiceOptions: Sequelize.HasManySetAssociationsMixin<ServiceOptionGI, number>;
- getServiceCategories: Sequelize.BelongsToManyGetAssociationsMixin<ServiceCategoryGI>;
- setServiceCategories: Sequelize.BelongsToManySetAssociationsMixin<ServiceCategoryGI, number, 'serviceLink'>;
- getResourceTypes: Sequelize.BelongsToManyGetAssociationsMixin<ResourceTypeGI>;
- setResourceTypes: Sequelize.BelongsToManySetAssociationsMixin<ResourceTypeGI, number, ServiceResourceTypeLinkGA>;
- getResources: Sequelize.BelongsToManyGetAssociationsMixin<ResourceGI>;
- setResources: Sequelize.BelongsToManySetAssociationsMixin<ResourceGI, number, ServiceResourceLinkGA>;
- getBookingOptions: Sequelize.BelongsToManyGetAssociationsMixin<BookingOptionGI>;
- setBookingOptions: Sequelize.BelongsToManySetAssociationsMixin<BookingOptionGI, number, 'service_booking_option_link'>;
- getNotificationTypes: Sequelize.BelongsToManyGetAssociationsMixin<NotificationTypeGI>;
- setNotificationType: Sequelize.BelongsToManySetAssociationsMixin<NotificationTypeGI, number, 'notification_type_service_link'>;
- isIncludeResource(id: number): Promise<boolean | Error>
- hasSurvey(type: string): Promise<boolean>
- isBookingOption(bookingOptions: number[]): Promise<boolean | Error>
- getActualPrice(config: {customer: {id: number, membership_id? :number}, resources: ResourceGI[]}, priceRulres: PriceRuleGI[]): PriceRuleGI
- getAvailability(): Promise<Availability | null>
- loadPriceRules(): Promise<null>
- loadPriceConditions(config: {customer: {id: number, membership_id? :number}, resources: any[]}): Promise<{customer: {id: number, membership_id? :number}, resources: ResourceGI[]}>
- }
- export interface ServiceCM extends Sequelize.Model<ServiceGI, ServiceGA> {}
- let attributes: Sequelize.DefineAttributes = {
- id: {
- type: Sequelize.INTEGER,
- autoIncrement: true,
- primaryKey: true
- },
- name: Sequelize.STRING,
- type: Sequelize.ENUM('type1', 'type2'),
- working_hours: Sequelize.TEXT,
- non_available_schedule: Sequelize.TEXT,
- min_duration: Sequelize.INTEGER,
- max_duration: Sequelize.INTEGER,
- default_duration: Sequelize.INTEGER,
- time_gap: Sequelize.INTEGER,
- min_booking_interval: Sequelize.INTEGER,
- max_booking_interval: Sequelize.INTEGER,
- check_in_time: Sequelize.INTEGER,
- check_out_time: Sequelize.INTEGER,
- availability: Sequelize.JSON,
- cancel_gap: {
- type: Sequelize.INTEGER,
- defaultValue: 0
- },
- slot_duration: {
- type: Sequelize.INTEGER,
- defaultValue: 60, // sec
- get () {
- let d = this.getDataValue('slot_duration')
- if (!d)
- return 60
- return d
- }
- },
- price: {
- type: Sequelize.VIRTUAL,
- },
- ...localizationMixin([
- 'name',
- ]),
- deletedAt: {
- type: Sequelize.DATE,
- get () {
- return moment(this.getDataValue('deletedAt'))
- }
- },
- createdAt: {
- type: Sequelize.DATE,
- get () {
- return moment(this.getDataValue('createdAt'))
- }
- },
- updatedAt: {
- type: Sequelize.DATE,
- get () {
- return moment(this.getDataValue('createdAt'))
- }
- },
- }
- export default (seq: Sequelize.Sequelize) => {
- var model = seq.define<ServiceGI, ServiceGA>("Service", attributes, {
- tableName: 'services',
- paranoid: true,
- })
- model['prototype'].getAvailability = async function(this: ServiceGI) {
- let service = await model.findById(this.id, {attributes: ['availability']})
- return service.availability ? new Availability(<IAvailabilityConfig>service.availability) : null
- }
- model['prototype'].loadPriceRules = async function() {
- await this.reload({
- attributes: ['name', 'min_duration', 'max_duration', 'slot_duration'],
- include: [
- {
- model: db.Location,
- attributes: ['id']
- },
- ...db.PriceRule.getPriceRuleConfig()
- ]
- })
- if (this.PriceRules.length == 0)
- throw new Error(`Service ${this.name} doesn't have price rule.`)
- }
- model['prototype'].loadPriceConditions = async function(config: {customer: {id: number, membership_id? :number}, resources: any[]}) {
- if (!config.customer.membership_id || !config.customer.membership_id === undefined) {
- let _customerPayload = await db.Customer.findById(config.customer.id, {attributes: ['id', 'membership_id']})
- config.customer.membership_id = _customerPayload.membership_id
- }
- if (!config.resources['ResourceTypes']) {
- config.resources = await db.Resource.findAll({
- where: {
- id: {$in: config.resources}
- },
- include: [{
- model: db.ResourceType
- }]
- })
- }
- return config
- }
- /**
- * Function should be sync!!!
- * @param {{customer: {id: number; membership_id?: number}; resources: any[]}} config
- * @return {Promise<number | Error>}
- */
- model['prototype'].getActualPrice= function (
- this: ServiceGI,
- config: {customer: {id: number, membership_id? :number}, resources: ResourceGI[]},
- priceRulres: PriceRuleGI[]
- )
- {
- // model['prototype'].loadPriceRules should be loaded before
- let price;
- for (let rule of priceRulres) {
- if (rule.Memberships.length > 0) {
- if (!rule.Memberships.some(membership => membership.id === config.customer.membership_id)) {
- continue;
- }
- }
- if (rule.ResourceTypes.length > 0) {
- let st = rule.ResourceTypes.some(resType => {
- return config.resources.some(res => {
- return res.ResourceTypes.some(rt => {
- return rt.id === resType.id
- })
- })
- })
- if (!st) {
- continue
- }
- }
- if (rule.Resources.length > 0) {
- let st = rule.Resources.some(resource => {
- return config.resources.some(r => {
- return r.id === resource.id
- })
- })
- if (!st) {
- continue
- }
- }
- if (rule.Locations.length > 0) {
- let st = rule.Locations.some(location => {
- return this.Locations.some(loc => {
- return location.id === loc.id
- })
- })
- if (!st) {
- continue
- }
- }
- if (rule.Customers.length > 0) {
- if (!rule.Customers.some(cm => cm.id === config.customer.id)) {
- continue
- }
- }
- if (!price) {
- price = rule
- } else {
- if (rule.priority > price.priority) {
- price = rule
- }
- }
- }
- if (!price) {
- throw new PriceNotFound(`Price rules are not matched`)
- }
- return price
- }
- model['prototype'].hasSurvey = async function(this: ServiceGI, type: string) {
- let s = {}
- switch (type) {
- case 'checked_in':
- s['survey_check_in_id'] = {$ne: null};
- break;
- case 'checked_out':
- s['survey_check_out_id'] = {$ne: null};
- break;
- }
- let count = await model.count({
- where: {
- id: this.id,
- ...s
- }
- })
- return count > 0
- }
- model['prototype'].isIncludeResource = async function(id: number) {
- let c = await model.count({
- where: {
- id: this.id
- },
- include: [
- {
- model: db.Resource,
- required: true,
- where: {
- id
- }
- }
- ]
- })
- if (!c) {
- throw new Error(`Resource doesn't associate to service`)
- }
- }
- model['prototype'].isBookingOption = async function (this: ServiceGI, bookingOptions: number[]) {
- if (bookingOptions.length === 0 ) return true
- let count = await db.BookingOption.count({
- where: {
- id: {$in: bookingOptions}
- },
- include: [
- {
- model: db.Service,
- where: {
- id: this.id
- }
- }
- ]})
- if (count !== bookingOptions.length) {
- throw new Error(`Some of booking options doesn't included to service`);
- }
- return true
- }
- model['i18nUpdate'] = i18nUpdate
- model['prototype'].getI18nTitle = getI18nTitle;
- model['associate'] = function (db: SequelizeModels) {
- let {
- Location, Survey, ServiceOption, ServiceCategory,
- ServiceResourceTypeLink, ResourceType, ServiceResourceLink,
- Resource, NotificationType, Membership, BookingOption
- } = db
- model.belongsToMany(Location, {through: 'service_location_link', foreignKey: 'service_id'});
- model.hasMany(ServiceOption, {foreignKey: 'service_id', as: 'service_options'})
- model.belongsTo(Survey, {foreignKey: 'survey_check_in_id', as: 'survey_check_in'})
- model.belongsTo(Survey, {foreignKey: 'survey_check_out_id', as: 'survey_check_out'})
- model.belongsToMany(ServiceCategory, {through: 'service_link', foreignKey: 'service_category_id'});
- model.belongsToMany(ResourceType, {through: {model: ServiceResourceTypeLink, unique: false}, foreignKey: 'service_id'});
- model.belongsToMany(Resource, {through: {model: ServiceResourceLink, unique: false}, foreignKey: 'service_id'});
- model.belongsToMany(NotificationType, {through: 'notification_type_service_link', foreignKey: 'service_id'});
- model.belongsToMany(Membership, {through: 'membership_service_link', foreignKey: 'service_id'})
- model.belongsToMany(BookingOption, {through: 'service_booking_option_link', foreignKey: 'service_id'})
- model.belongsToMany(db.PriceRule, {through: 'service_price_rule_link', foreignKey: 'service_id'})
- }
- return model;
- }
Add Comment
Please, Sign In to add comment