UNPKG

@accounter/server

Version:
178 lines (160 loc) • 6.7 kB
import DataLoader from 'dataloader'; import { Injectable, Scope } from 'graphql-modules'; import { sql } from '@pgtyped/runtime'; import { reassureOwnerIdExists } from '../../../shared/helpers/index.js'; import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js'; import { TenantAwareDBClient } from '../../app-providers/tenant-db-client.js'; import type { DateOrString, IAddBusinessTripAttendeesParams, IAddBusinessTripAttendeesQuery, IGetBusinessTripsAttendeesByBusinessTripIdsQuery, IGetBusinessTripsAttendeesByBusinessTripIdsResult, IGetBusinessTripsByAttendeeIdQuery, IGetBusinessTripsByChargeIdsResult, IGetLastFlightByDateAndAttendeeIdQuery, IRemoveBusinessTripAttendeesParams, IRemoveBusinessTripAttendeesQuery, IUpdateBusinessTripAttendeeParams, IUpdateBusinessTripAttendeeQuery, } from '../types.js'; import { BusinessTripsProvider } from './business-trips.provider.js'; const getBusinessTripsAttendeesByBusinessTripIds = sql<IGetBusinessTripsAttendeesByBusinessTripIdsQuery>` SELECT bta.business_trip_id, bta.arrival, bta.departure, fe.*, b.vat_number, b.hebrew_name, b.address, b.address_hebrew, b.email, b.website, b.phone_number, b.country, b.no_invoices_required, b.suggestion_data, b.can_settle_with_receipt, b.exempt_dealer, b.optional_vat, b.pcn874_record_type_override, b.city, b.zip_code FROM accounter_schema.financial_entities fe LEFT JOIN accounter_schema.business_trips_attendees bta ON bta.attendee_business_id = fe.id LEFT JOIN accounter_schema.businesses b ON bta.attendee_business_id = b.id WHERE bta.business_trip_id IN $$businessTripIds;`; const getBusinessTripsByAttendeeId = sql<IGetBusinessTripsByAttendeeIdQuery>` SELECT DISTINCT bt.* FROM accounter_schema.business_trips_attendees bta LEFT JOIN accounter_schema.business_trips bt ON bt.id = bta.business_trip_id WHERE bta.attendee_business_id = $attendeeId;`; const getLastFlightByDateAndAttendeeId = sql<IGetLastFlightByDateAndAttendeeIdQuery>` SELECT * FROM accounter_schema.business_trips_attendees WHERE attendee_business_id = $attendeeBusinessId AND arrival < $date AND departure <= $date AND departure >= $date - INTERVAL '14 DAY' ORDER BY departure DESC FETCH FIRST 1 ROWS ONLY;`; const addBusinessTripAttendees = sql<IAddBusinessTripAttendeesQuery>` INSERT INTO accounter_schema.business_trips_attendees (business_trip_id, attendee_business_id, arrival, departure, owner_id) VALUES ($businessTripId, $businessId, $arrival, $departure, $ownerId) ON CONFLICT DO NOTHING RETURNING *;`; const updateBusinessTripAttendee = sql<IUpdateBusinessTripAttendeeQuery>` UPDATE accounter_schema.business_trips_attendees SET arrival = COALESCE( $arrival, arrival ), departure = COALESCE( $departure, departure ) WHERE business_trip_id = $businessTripId AND attendee_business_id = $attendeeBusinessId RETURNING *; `; const removeBusinessTripAttendees = sql<IRemoveBusinessTripAttendeesQuery>` DELETE FROM accounter_schema.business_trips_attendees WHERE business_trip_id = $businessTripId AND attendee_business_id = $businessId RETURNING *;`; @Injectable({ scope: Scope.Operation, global: true, }) export class BusinessTripAttendeesProvider { constructor( private db: TenantAwareDBClient, private adminContextProvider: AdminContextProvider, private businessTripsProvider: BusinessTripsProvider, ) {} private async batchBusinessTripsAttendeesByChargeIds(chargeIds: readonly string[]) { const businessTripsMatches = await this.businessTripsProvider.getBusinessTripsByChargeIdLoader .loadMany(chargeIds) .then( res => res.filter( item => item && !(item instanceof Error), ) as IGetBusinessTripsByChargeIdsResult[], ); const businessTripsAttendees = await this.getBusinessTripsAttendeesByBusinessTripIdLoader .loadMany(businessTripsMatches.filter(record => record.id).map(record => record.id)) .then( records => records .flat() .filter( record => !(record instanceof Error), ) as IGetBusinessTripsAttendeesByBusinessTripIdsResult[], ); return chargeIds.map(id => businessTripsMatches .filter(record => record.charge_id === id) .map(match => businessTripsAttendees.filter(attendee => attendee.business_trip_id === match.id), ) .flat(), ); } public getBusinessTripsAttendeesByChargeIdLoader = new DataLoader( (chargeIds: readonly string[]) => this.batchBusinessTripsAttendeesByChargeIds(chargeIds), { cache: false, }, ); private async batchBusinessTripsAttendeesByBusinessTripIds(businessTripIds: readonly string[]) { const businessTrips = await getBusinessTripsAttendeesByBusinessTripIds.run( { businessTripIds, }, this.db, ); return businessTripIds.map(id => businessTrips.filter(record => record.business_trip_id === id), ); } public getBusinessTripsAttendeesByBusinessTripIdLoader = new DataLoader( (ids: readonly string[]) => this.batchBusinessTripsAttendeesByBusinessTripIds(ids), ); public async getBusinessTripsByAttendeeId(attendeeId: string) { return getBusinessTripsByAttendeeId.run({ attendeeId }, this.db); } public async getLastFlightByDateAndAttendeeId(params: { attendeeBusinessId: string; date: DateOrString; }) { return getLastFlightByDateAndAttendeeId.run(params, this.db); } public async addBusinessTripAttendees(params: IAddBusinessTripAttendeesParams) { if (params.businessTripId) { this.getBusinessTripsAttendeesByBusinessTripIdLoader.clear(params.businessTripId); } const { ownerId } = await this.adminContextProvider.getVerifiedAdminContext(); return addBusinessTripAttendees.run(reassureOwnerIdExists(params, ownerId), this.db); } public async updateBusinessTripAttendee(params: IUpdateBusinessTripAttendeeParams) { if (params.businessTripId) { this.getBusinessTripsAttendeesByBusinessTripIdLoader.clear(params.businessTripId); } return updateBusinessTripAttendee.run(params, this.db); } public async removeBusinessTripAttendees(params: IRemoveBusinessTripAttendeesParams) { if (params.businessTripId) { this.getBusinessTripsAttendeesByBusinessTripIdLoader.clear(params.businessTripId); } return removeBusinessTripAttendees.run(params, this.db); } public clearCache() { this.getBusinessTripsAttendeesByChargeIdLoader.clearAll(); this.getBusinessTripsAttendeesByBusinessTripIdLoader.clearAll(); } }