\n\t\t{{ data ? data.logTs : 'Date / Updated User'\n\t\t}} - {{ this.updatedUser ? this.updatedUser.substring(0, 5) + '...' : 'N/A' }}\n\t
\n\t{{ key }}
\n\t\n\t\t{{ (displayAllData ? column[1] : jsonDifferences.includes(column[0])) ? column[1] : ' ' }}\n\t
\n = new Subject();\n\n\tconstructor(private http: HttpClient) {}\n\n\tfindAll(): void {\n\t\tthis.http.get(`${this.baseUrl}`).subscribe((response: Code[]) => {\n\t\t\tthis.codeSubject.next(response);\n\t\t});\n\t}\n\n\tfindPriceConfigCodes(): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/price-configs`);\n\t}\n\n\tfindByType(codeType: string): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/${codeType}`);\n\t}\n\n\tfindOne(id: number): Observable {\n\t\treturn this.http.get(`${this.baseUrl}${id}`);\n\t}\n\n\tupdate(id: number, code: Partial): Observable {\n\t\treturn this.http.patch(`${this.baseUrl}/${code.id}`, code);\n\t}\n\n\tcreate(code: Partial): Observable {\n\t\treturn this.http.post(`${this.baseUrl}`, code);\n\t}\n\n\tdelete(id: number): Observable {\n\t\treturn this.http.delete(`${this.baseUrl}/${id}`);\n\t}\n\n incrementCodeValue(incrementInfo: IncrementInfo): Observable {\n return this.http.post(`${this.baseUrl}/increment`, incrementInfo)\n }\n}\n","import {Injectable} from '@angular/core';\nimport {Observable, Subject} from 'rxjs';\nimport {HttpClient} from '@angular/common/http';\nimport {environment} from '../../../environments/environment';\nimport {Contact} from '../models/contact.model';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class ContactService {\n\tbaseUrl = `${environment.url}/contact`;\n\tcontactsSubject: Subject = new Subject();\n\n\tconstructor(private http: HttpClient) {}\n\n\tcreate(contact: Contact): Observable {\n\t\treturn this.http.post(this.baseUrl, contact);\n\t}\n\n\tcreateContactWithXref(contact: Contact, refType: string, refId: string): Observable {\n\t\treturn this.http.post(`${this.baseUrl}/${refType}/${refId}`, contact);\n\t}\n\n\tdeleteContactAssociation(contactId: number, refId: string, refType: string) {\n\t\treturn this.http.delete(`${this.baseUrl}/${contactId}/${refType}/${refId}`);\n\t}\n\n\tfindAll(): Observable {\n\t\tthis.http.get(this.baseUrl).subscribe(\n\t\t\t(contacts) => {\n\t\t\t\tthis.contactsSubject.next(contacts);\n\t\t\t},\n\t\t\t(error) => {\n\t\t\t\tthrow new Error(error);\n\t\t\t}\n\t\t);\n\t\treturn this.contactsSubject.asObservable();\n\t}\n\n\tfindContactsByType(id: string, type: string): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/${type}/${id}`);\n\t}\n\n findContactsForQuoteResend(clientId: string, quoteId: number): Observable {\n return this.http.get(`${this.baseUrl}/quote/${quoteId}/client/${clientId}`);\n }\n\n\tfindOne(id: number): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/${id}`);\n\t}\n\n\tupdate(contactWithId: Contact): Observable {\n\t\treturn this.http.put(`${this.baseUrl}/${contactWithId.id}`, contactWithId);\n\t}\n\n\tpatch(contactWithId: Contact): Observable {\n\t\treturn this.http.patch(`${this.baseUrl}/${contactWithId.id}`, contactWithId);\n\t}\n\n\tremove(id: number): Observable {\n\t\treturn this.http.delete(`${this.baseUrl}/${id}`);\n\t}\n\n\tgetInternal(): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/internal`);\n\t}\n\n\tfindByType(type: string, typeId: number): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/type/${type.toUpperCase()}/${typeId}`);\n\t}\n\n\tfindByClient(id: number, siteOnly: boolean): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/client/${id}/${siteOnly ? 'site' : ''}`);\n\t}\n}\n","import {Injectable} from '@angular/core';\nimport {WeightUnitEnum} from '../enums/weight-unit.enum';\nimport {DimensionUnitEnum} from '../enums/dimension-unit.enum';\nimport {HandlingUnit} from '../models/handling-unit.model';\nimport {FormGroup} from '@angular/forms';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class FreightDetailCalculationService {\n\tconstructor() {}\n\n\tweightConversion: any = {\n\t\t[WeightUnitEnum.POUND]: {\n\t\t\t[WeightUnitEnum.POUND]: 1,\n\t\t\t[WeightUnitEnum.KILOGRAM]: 0.453592\n\t\t},\n\t\t[WeightUnitEnum.KILOGRAM]: {\n\t\t\t[WeightUnitEnum.POUND]: 2.205,\n\t\t\t[WeightUnitEnum.KILOGRAM]: 1\n\t\t}\n\t};\n\n\tdimensionConversion: any = {\n\t\t[DimensionUnitEnum.FOOT]: {\n\t\t\t[DimensionUnitEnum.FOOT]: 1,\n\t\t\t[DimensionUnitEnum.INCH]: 12,\n\t\t\t[DimensionUnitEnum.METER]: 0.3048,\n\t\t\t[DimensionUnitEnum.CENTIMETER]: 30.48\n\t\t},\n\t\t[DimensionUnitEnum.INCH]: {\n\t\t\t[DimensionUnitEnum.FOOT]: 0.0833333,\n\t\t\t[DimensionUnitEnum.INCH]: 1,\n\t\t\t[DimensionUnitEnum.METER]: 0.0254,\n\t\t\t[DimensionUnitEnum.CENTIMETER]: 2.54\n\t\t},\n\t\t[DimensionUnitEnum.METER]: {\n\t\t\t[DimensionUnitEnum.FOOT]: 3.28084,\n\t\t\t[DimensionUnitEnum.INCH]: 39.3701,\n\t\t\t[DimensionUnitEnum.METER]: 1,\n\t\t\t[DimensionUnitEnum.CENTIMETER]: 100\n\t\t},\n\t\t[DimensionUnitEnum.CENTIMETER]: {\n\t\t\t[DimensionUnitEnum.FOOT]: 0.0328084,\n\t\t\t[DimensionUnitEnum.INCH]: 0.393701,\n\t\t\t[DimensionUnitEnum.METER]: 0.01,\n\t\t\t[DimensionUnitEnum.CENTIMETER]: 1\n\t\t}\n\t};\n\n\tpalletWidth = 48;\n\tpalletWidthUnit = DimensionUnitEnum.INCH;\n\n\tpalletLength = 48;\n\tpalletLengthUnit = DimensionUnitEnum.INCH;\n\n\trowSize = 2;\n\n\tgetTotalLinearDimensions(handlingUnitsGroup: FormGroup[], unit: string | null): number {\n\t\tlet handlingUnits: HandlingUnit[] = [];\n\t\tif (unit) {\n\t\t\thandlingUnitsGroup.forEach((handlingUnitGroup) => {\n\t\t\t\tconst handlingUnit = handlingUnitGroup.value as HandlingUnit;\n\t\t\t\tif (handlingUnit.length && handlingUnit.width && handlingUnit.height && handlingUnit.wUnit && handlingUnit.qty) {\n\t\t\t\t\thandlingUnits.push(handlingUnit);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn this.calculateLinearDimension(handlingUnits, unit);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tgetTotalWeight(handlingUnits: FormGroup[], unit: string | null): number {\n\t\tlet totalWeight = 0;\n\t\tif (unit) {\n\t\t\thandlingUnits.forEach((handlingUnitGroup) => {\n\t\t\t\tconst handlingUnit = handlingUnitGroup.value as HandlingUnit;\n\t\t\t\tif (handlingUnit.weight && handlingUnit.wUnit && handlingUnit.qty) {\n\t\t\t\t\ttotalWeight += this.convertWeight(handlingUnit.weight, handlingUnit.wUnit, unit) * handlingUnit.qty;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn totalWeight;\n\t}\n\n\tgetTotalSkids(handlingUnits: FormGroup[]): number {\n\t\tlet totalSkids = 0;\n\t\tlet singleLength = 0;\n\t\tlet wideLength = 0;\n\t\thandlingUnits.forEach((handlingUnitGroup) => {\n\t\t\tconst handlingUnit = handlingUnitGroup.value as HandlingUnit;\n\t\t\tif (handlingUnit.length && handlingUnit.width && handlingUnit.dUnit && handlingUnit.qty) {\n\t\t\t\tif (this.convertDimension(handlingUnit.width, handlingUnit.dUnit, this.palletWidthUnit) > this.palletWidth) {\n\t\t\t\t\twideLength += handlingUnit.qty * this.convertDimension(handlingUnit.length, handlingUnit.dUnit, this.palletLengthUnit);\n\t\t\t\t} else {\n\t\t\t\t\tsingleLength += handlingUnit.qty * this.convertDimension(handlingUnit.length, handlingUnit.dUnit, this.palletLengthUnit);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\ttotalSkids += 2 * Math.ceil(wideLength / this.palletLength);\n\t\ttotalSkids += Math.ceil(singleLength / this.palletLength);\n\t\treturn totalSkids;\n\t}\n\n\tconvertWeight(value: number, fromUnit: string, toUnit: string): number {\n\t\treturn value * this.weightConversion[fromUnit][toUnit];\n\t}\n\n\tconvertDimension(value: number, fromUnit: string, toUnit: string): number {\n\t\treturn value * this.dimensionConversion[fromUnit][toUnit];\n\t}\n\n\tcalculateLinearDimension(handlingUnits: HandlingUnit[], dimensionUOM: string): number {\n\t\treturn (\n\t\t\tthis.calculateSingleRowLinearDimension(this.getSingleRows(handlingUnits), dimensionUOM) +\n\t\t\tthis.calculateStackedRowLinearDimension(this.getStackedRows(handlingUnits), dimensionUOM)\n\t\t);\n\t}\n\n\t/**\n\t * calculate linear dimensions\n\t * the rough equation for how to handle it in the code is as follows\n\t * total units = math.ceil(sum of units quantity / number of items per row)\n\t * create an array of length, convert the lengths to the correct dimension\n\t * sort lengths largest first, slice the total number of pallets, find the sum\n\t * return the sum found\n\t * if no length then return 0\n\t * @param handlingUnits\n\t * @param dimensionUOM\n\t * @param itemsPerRow\n\t * @returns\n\t */\n\tcalculateStackedRowLinearDimension(handlingUnits: HandlingUnit[], dimensionUOM: string, itemsPerRow: number = this.rowSize): number {\n\t\t// get the total number of handling units for stacked rows\n\t\tconst totalPieces: number = Math.ceil(\n\t\t\thandlingUnits\n\t\t\t\t// if there is no total pieces we are going to assume there is 1\n\t\t\t\t.map((handlingUnit: HandlingUnit) => (handlingUnit.qty ? handlingUnit.qty : 1))\n\t\t\t\t.reduce((previousDimension, currentDimension) => previousDimension + currentDimension, 0) / itemsPerRow\n\t\t);\n\t\t// figure out the total number of pieces that we can use to calculate the liner dimension\n\t\t// basically if there is an odd number we want to add 1 to it\n\t\tconst lengths: number[] = [];\n\t\t// extract the lengths\n\t\t// this is a bit more tricky since we need to get the total lengths, and if there is more than one handling unit\n\t\t// in the qty then we have to handle that here too\n\t\thandlingUnits.forEach((handlingUnit: HandlingUnit) => {\n\t\t\t// if there is no length then we do not want to assume what the length is\n\t\t\tif (handlingUnit.length && handlingUnit.dUnit) {\n\t\t\t\tconst amount = handlingUnit.qty ? handlingUnit.qty : 1;\n\n\t\t\t\t// for each qty of the handling unit add it to the array\n\t\t\t\tfor (let numb = 0; numb < amount; numb++) {\n\t\t\t\t\t// convert the handling unit\n\t\t\t\t\tlengths.push(this.convertDimension(handlingUnit.length, handlingUnit.dUnit, dimensionUOM));\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tlet totalLength = 0;\n\t\t// get stacked row lengths\n\t\tif (lengths.length > 0) {\n\t\t\t// sort length\n\t\t\ttotalLength = lengths\n\t\t\t\t.sort((lengthA: number, lengthB: number) => lengthB - lengthA)\n\t\t\t\t// find the correct amount of lengths we need to reduce on\n\t\t\t\t.slice(0, totalPieces)\n\t\t\t\t// reduce\n\t\t\t\t.reduce((previousLength: number, currentLength: number) => previousLength + currentLength, 0);\n\t\t}\n\t\treturn totalLength;\n\t}\n\n\tcalculateSingleRowLinearDimension(handlingUnits: HandlingUnit[], dimensionUOM: string): number {\n\t\tlet totalLength = 0;\n\t\thandlingUnits.forEach((handlingUnit) => {\n\t\t\tif (handlingUnit.length && handlingUnit.dUnit) {\n\t\t\t\ttotalLength += this.convertDimension(handlingUnit.length, handlingUnit.dUnit, dimensionUOM);\n\t\t\t}\n\t\t});\n\t\treturn totalLength;\n\t}\n\n\tgetSingleRows(handlingUnits: HandlingUnit[]): HandlingUnit[] {\n\t\treturn handlingUnits.filter((handlingUnit) => {\n\t\t\tif (handlingUnit.width && handlingUnit.dUnit) {\n\t\t\t\treturn this.convertDimension(handlingUnit.width, handlingUnit.dUnit, this.palletWidthUnit) > this.palletWidth;\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t}\n\n\tgetStackedRows(handlingUnits: HandlingUnit[]): HandlingUnit[] {\n\t\treturn handlingUnits.filter((handlingUnit) => {\n\t\t\tif (handlingUnit.width && handlingUnit.dUnit) {\n\t\t\t\treturn this.convertDimension(handlingUnit.width, handlingUnit.dUnit, this.palletWidthUnit) <= this.palletWidth;\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t}\n}\n","import {Injectable} from '@angular/core';\nimport {environment} from '../../../environments/environment';\nimport {HttpClient} from '@angular/common/http';\nimport {Observable} from 'rxjs';\nimport {FreightBroker} from '../models/freight-broker.interface';\nimport {FreightBid} from '../models/freight-bid.interface';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class FreightService {\n\tbaseUrl: string = `${environment.url}/freight`;\n\tconstructor(private http: HttpClient) {}\n\n\tfindAllBrokersByShipmentIds(ids: number[]): Observable {\n\t\treturn this.http.post(`${this.baseUrl}/brokers-shipments`, ids);\n\t}\n\n\trequestRates(ids: number[], freightBrokers: FreightBroker[], projectId: number | undefined): Observable {\n\t\tlet params = {\n\t\t\tparams: {}\n\t\t};\n\t\tif (projectId) {\n\t\t\tconst activityDesc = freightBrokers.map((broker) => (broker.name ? `${broker.name}` : '')).join(', ');\n\t\t\tparams.params = {\n\t\t\t\tactivityType: 'FREIGHT_RATE',\n\t\t\t\tprojectId: projectId,\n\t\t\t\tdescription: `request rates from ${activityDesc}`\n\t\t\t};\n\t\t}\n\t\treturn this.http.post(\n\t\t\t`${this.baseUrl}/rates`,\n\t\t\t{\n\t\t\t\tshipmentIds: ids,\n\t\t\t\tbrokers: freightBrokers\n\t\t\t},\n\t\t\tparams\n\t\t);\n\t}\n\n\tbookFreight(bid: FreightBid, projectId: number | undefined): Observable {\n\t\tlet params = {\n\t\t\tparams: {}\n\t\t};\n\t\tif (projectId) {\n\t\t\tparams.params = {\n\t\t\t\tactivityType: 'FREIGHT_BID',\n\t\t\t\tprojectId: projectId,\n\t\t\t\tdescription: `request to book a shipment with ${bid.brokerName ? bid.brokerName : bid.carrierName}`\n\t\t\t};\n\t\t}\n\t\treturn this.http.get(`${this.baseUrl}/book/${bid.id}`, params);\n\t}\n\n\tgetBol(bidId: number): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/book/bol/${bidId}`);\n\t}\n}\n","import {Injectable} from '@angular/core';\nimport {HttpClient} from '@angular/common/http';\nimport {environment} from '../../../environments/environment';\nimport {Observable, Subject} from 'rxjs';\nimport {GlCode} from '../models/gl-code.interface';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class GlCodeService {\n\tbaseUrl: string = `${environment.url}/core/gl-codes`;\n\tglCodeSubject: Subject = new Subject();\n\tconstructor(private http: HttpClient) {}\n\n\tfindAll(): Observable {\n\t\treturn this.http.get(this.baseUrl);\n\t}\n\n\tsubjectFindAll(): void {\n\t\tthis.http.get(this.baseUrl).subscribe((response) => {\n\t\t\tthis.glCodeSubject.next(response);\n\t\t});\n\t}\n\n\tfindOne(id: number): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/${id}`);\n\t}\n\n\tcreate(glCode: GlCode): Observable {\n\t\treturn this.http.post(this.baseUrl, glCode);\n\t}\n\n\tupdate(id: number | undefined, glCode: GlCode): Observable {\n\t\treturn this.http.put(`${this.baseUrl}/${id}`, glCode);\n\t}\n\n\tremove(id: number): Observable {\n\t\treturn this.http.delete(`${this.baseUrl}/${id}`);\n\t}\n}\n","import {Injectable} from '@angular/core';\nimport {Observable} from 'rxjs';\nimport {environment} from '../../../environments/environment';\nimport {HttpClient, HttpParams} from '@angular/common/http';\nimport {InstallCalendar} from '../models/install-calendar.interface';\nimport {addDays, isWeekend} from 'date-fns';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class InstallCalendarService {\n\tbaseUrl: string = `${environment.url}/install-calendar`;\n\tconstructor(private http: HttpClient) {}\n\n\tgetInstallCalendar(selectedDate: Date | null = null): Observable {\n\t\tlet params = new HttpParams();\n\t\tif (selectedDate) {\n\t\t\tparams = params.append('selectedDate', selectedDate.toISOString().substring(0, 10));\n\t\t}\n\t\treturn this.http.get(`${this.baseUrl}`, {params: params});\n\t}\n\n\tcalcEndDate(startDate: Date | null, duration: number | null, weekends: boolean | null): Date | null {\n\t\tlet endDate: Date;\n\n\t\tif (!weekends) {\n\t\t\tweekends = false;\n\t\t}\n\t\tif (!duration) {\n\t\t\tduration = 0;\n\t\t}\n\t\tduration = Math.floor(duration);\n\t\tif (startDate) {\n\t\t\tendDate = new Date(startDate);\n\t\t\tif (!weekends) {\n\t\t\t\twhile (isWeekend(endDate)) {\n\t\t\t\t\tendDate = addDays(endDate, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\twhile (duration > 1) {\n\t\t\t\tendDate = addDays(endDate, 1);\n\t\t\t\tif (!weekends) {\n\t\t\t\t\twhile (isWeekend(endDate)) {\n\t\t\t\t\t\tendDate = addDays(endDate, 1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tduration--;\n\t\t\t}\n\t\t\treturn endDate;\n\t\t}\n\t\treturn null;\n\t}\n}\n","import {Injectable} from '@angular/core';\nimport {environment} from '../../../environments/environment';\nimport {Observable, Subject} from 'rxjs';\nimport {HttpClient} from '@angular/common/http';\nimport {InstallLocation} from '../models/install-location.interface';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class InstallLocationService {\n\tbaseUrl: string = `${environment.url}/core/install-locations`;\n\tinstallLocationSubject: Subject = new Subject();\n\tconstructor(private http: HttpClient) {}\n\n\tfindAll(): void {\n\t\tthis.http.get(this.baseUrl).subscribe((response) => {\n\t\t\tthis.installLocationSubject.next(response);\n\t\t});\n\t}\n\n\tfindOne(id: number): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/${id}`);\n\t}\n\n\tcreate(installLocation: InstallLocation): Observable {\n\t\treturn this.http.post(this.baseUrl, installLocation);\n\t}\n\n\tupdate(installLocation: InstallLocation): Observable {\n\t\treturn this.http.put(this.baseUrl, installLocation);\n\t}\n\n\tdelete(id: number): void {\n\t\tthis.http.delete(`${this.baseUrl}/${id}`);\n\t}\n}\n","import {Injectable} from '@angular/core';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class LocalStorageService {\n\tsetItem(key: string, value: any) {\n\t\tlocalStorage.setItem(key, value);\n\t}\n\n\tgetItem(key: string): any {\n\t\treturn localStorage.getItem(key);\n\t}\n\n\tsetBool(key: string, value: boolean) {\n\t\tlocalStorage.setItem(key, String(value));\n\t}\n\n\tgetBool(key: string, notFound: boolean | null = null): boolean {\n\t\tconst val = localStorage.getItem(key);\n\t\tif (val === null && notFound !== null) {\n\t\t\treturn notFound;\n\t\t}\n\t\treturn val === 'true';\n\t}\n\n\tsetObject(key: string, value: object | null) {\n\t\tlocalStorage.setItem(key, JSON.stringify(value));\n\t}\n\n\tgetObject(key: string): object {\n\t\tconst obj = localStorage.getItem(key);\n\t\treturn obj ? JSON.parse(obj) : null;\n\t}\n}\n","import {Injectable} from '@angular/core';\nimport {HttpClient} from '@angular/common/http';\nimport {environment} from '../../../environments/environment';\nimport {Observable, Subject} from 'rxjs';\nimport {Location} from '../models/location.interface';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class LocationService {\n\tbaseUrl: string = `${environment.url}/location`;\n\tlocationSubject: Subject = new Subject();\n\tconstructor(private http: HttpClient) {}\n\n\tcreate(location: Location): Observable {\n\t\treturn this.http.post(this.baseUrl, location);\n\t}\n\n\tfindAll(): void {\n\t\tthis.http.get(this.baseUrl).subscribe((response) => {\n\t\t\tthis.locationSubject.next(response);\n\t\t});\n\t}\n\n\tfindOne(id: number): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/${id}`);\n\t}\n\n\tupdate(location: Location): Observable {\n\t\treturn this.http.put(`${this.baseUrl}/${location.id}`, location);\n\t}\n\n\tremove(id: number): Observable {\n\t\treturn this.http.delete(`${this.baseUrl}/${id}`);\n\t}\n}\n","import {Injectable} from '@angular/core';\nimport {webSocket, WebSocketSubject} from 'rxjs/webSocket';\nimport {WebSocketEventInterface} from '../models/web-socket-event.interface';\nimport {HttpClient} from '@angular/common/http';\nimport {environment} from '../../../environments/environment';\nimport {NotifyUsers} from '../models/notify-users.interface';\nimport {catchError, mergeMap, Observable, retryWhen, throwError, timer} from 'rxjs';\nimport {AuthService} from './auth.service';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class NotificationService {\n\tbaseUrl: string = `${environment.url}/notification`;\n\turl: string = environment.webSocketUrl;\n\tretryAttempts: number = 1;\n\n\tpublic sub: WebSocketSubject = webSocket(this.url);\n\n\tconstructor(private http: HttpClient, private authService: AuthService) {\n\t\tthis.sub\n\t\t\t.pipe(\n\t\t\t\tretryWhen((errors) =>\n\t\t\t\t\terrors.pipe(\n\t\t\t\t\t\tmergeMap((error, index) => {\n\t\t\t\t\t\t\tconsole.log(`Reconnecting... (attempt ${this.retryAttempts})`);\n\t\t\t\t\t\t\tthis.retryAttempts++;\n\t\t\t\t\t\t\treturn timer(5000); // Retry after a delay of 5 seconds\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t),\n\t\t\t\tcatchError((error) => {\n\t\t\t\t\tconsole.log('Error occurred:', error);\n\t\t\t\t\treturn throwError(error);\n\t\t\t\t})\n\t\t\t)\n\t\t\t.subscribe(\n\t\t\t\t(msg) => {\n\t\t\t\t\tif (msg.event === 'register-prompt') {\n\t\t\t\t\t\tthis.sub.next({event: 'register', data: this.authService.userDataSource.value?.id!});\n\t\t\t\t\t\tconsole.log('WebSocket connected!');\n\t\t\t\t\t\tthis.retryAttempts = 1;\n\t\t\t\t\t}\n\t\t\t\t}, // Called whenever there is a message from the server.\n\t\t\t\t(err) => console.log(err), // Called if at any point WebSocket API signals some kind of error.\n\t\t\t\t() => console.log('Websocket connection complete.') // Called when connection is closed (for whatever reason).\n\t\t\t);\n\t}\n\n\tmarkNotificationsAsRead(notifications: NotifyUsers[]): Observable {\n\t\treturn this.http.put(this.baseUrl, notifications);\n\t}\n\n\tdeleteNotification(id: number): Observable {\n\t\treturn this.http.delete(`${this.baseUrl}/${id}`);\n\t}\n\n\tdeleteAllNotifications(): Observable {\n\t\treturn this.http.delete(`${this.baseUrl}/clear-all`);\n\t}\n}\n","import {Injectable} from '@angular/core';\nimport {environment} from '../../../environments/environment';\nimport {Part} from '../models/part.interface';\nimport {BehaviorSubject, Observable} from 'rxjs';\nimport {HttpClient, HttpParams} from '@angular/common/http';\nimport {QuoteLine} from '../models/quote-line.interface';\nimport {PartData} from '../models/part-data.interface';\nimport {QuoteLineCategoryEnum} from '../enums/quote-line-category.enum';\nimport {PartCategoryEnum} from '../enums/part-category.enum';\nimport {ConfigTypeEnum} from '../enums/config-type.enum';\nimport {MatSnackBar} from '@angular/material/snack-bar';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class PartService {\n\tbaseUrl: string = `${environment.url}/part`;\n\n\tprivate partCatalogDataSource: BehaviorSubject = new BehaviorSubject([]);\n\treadonly partCatalog: Observable = this.partCatalogDataSource.asObservable();\n\n\tprivate partsDataSource: BehaviorSubject = new BehaviorSubject([]);\n\treadonly parts: Observable = this.partsDataSource.asObservable();\n\n\tprivate isLoadingSource: BehaviorSubject = new BehaviorSubject(false);\n\treadonly isLoading: Observable = this.isLoadingSource.asObservable();\n\tloading: boolean = false;\n\n\tprivate isInitialLoadingSource: BehaviorSubject = new BehaviorSubject(false);\n\treadonly isInitialLoading: Observable = this.isInitialLoadingSource.asObservable();\n\n\tconstructor(private http: HttpClient, private snackbar: MatSnackBar) {}\n\n\tfindAll(clientId: string, quoteDate?: string): void {\n\t\tlet params: HttpParams = new HttpParams();\n\n\t\tif (clientId) {\n\t\t\tparams = params.append('client', clientId);\n\t\t}\n\n\t\tif (quoteDate) {\n\t\t\tparams = params.append('quote-date', quoteDate);\n\t\t}\n\n\t\tthis.http.get(this.baseUrl, {params}).subscribe((parts: Part[]) => {\n\t\t\tthis.partCatalogDataSource.next(parts);\n\t\t});\n\t}\n\n\tfindAllFromErp(clientId?: string, quoteDate?: string, force: boolean = false, initial: boolean = false): void {\n\t\tif (!this.loading) {\n\t\t\tlet params: HttpParams = new HttpParams();\n\n\t\t\tif (clientId) {\n\t\t\t\tparams = params.append('client', clientId);\n\t\t\t}\n\n\t\t\tif (quoteDate) {\n\t\t\t\tparams = params.append('quote-date', quoteDate);\n\t\t\t}\n\n\t\t\tif (force) {\n\t\t\t\tparams = params.append('force', force);\n\t\t\t}\n\n\t\t\tthis.partsDataSource.next([]);\n\t\t\tthis.loading = true;\n\t\t\tthis.isLoadingSource.next(true);\n\t\t\tif (initial) {\n\t\t\t\tthis.isInitialLoadingSource.next(true);\n\t\t\t}\n\t\t\tthis.http.get(this.baseUrl + '/erp', {params}).subscribe(\n\t\t\t\t(parts: QuoteLine[]) => {\n\t\t\t\t\tconst data: PartData[] = [];\n\t\t\t\t\tconst rackSolidParts: Part[] = [];\n\t\t\t\t\tparts.forEach((part) => {\n\t\t\t\t\t\t// Create Parts for Manual Parts on Quote\n\t\t\t\t\t\tdata.push({\n\t\t\t\t\t\t\tpart: part,\n\t\t\t\t\t\t\tselected: false\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// Create Parts for Rack Solid Selection\n\t\t\t\t\t\tif (part.category === QuoteLineCategoryEnum.RACK_SOLID) {\n\t\t\t\t\t\t\tlet shelfDetails: ShelfDetails = {};\n\n\t\t\t\t\t\t\tif (part.type === PartCategoryEnum.SHELVES && part.erpItemRef) {\n\t\t\t\t\t\t\t\tshelfDetails = PartService.getShelfDetailsFromPartNumber(part.erpItemRef);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\trackSolidParts.push({\n\t\t\t\t\t\t\t\t...shelfDetails,\n\t\t\t\t\t\t\t\tpartNumber: part.erpItemRef,\n\t\t\t\t\t\t\t\tdescription: part.description,\n\t\t\t\t\t\t\t\tprice: part.price,\n\t\t\t\t\t\t\t\tweight: part.weight,\n\t\t\t\t\t\t\t\tcategory: part.type as PartCategoryEnum,\n\t\t\t\t\t\t\t\terpItemRef: part.erpItemRef\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\t// TODO Have rack solid parts replace part catalog call\n\t\t\t\t\tthis.partsDataSource.next(data);\n\t\t\t\t\tthis.loading = false;\n\t\t\t\t\tthis.isLoadingSource.next(false);\n\t\t\t\t\tthis.isInitialLoadingSource.next(false);\n\t\t\t\t},\n\t\t\t\t(error) => {\n\t\t\t\t\tthis.loading = false;\n\t\t\t\t\tthis.isLoadingSource.next(false);\n\t\t\t\t\tthis.isInitialLoadingSource.next(false);\n\t\t\t\t\tthis.snackbar.open(error?.message ?? 'Failed to reload parts, please try again.');\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate static getShelfDetailsFromPartNumber(partNumber: string): ShelfDetails {\n\t\tconst match = partNumber.match(/^([A-Z]+)(\\d{2})(\\d{2})$/);\n\t\tif (!match) {\n\t\t\tconsole.error(`Invalid input string: ${partNumber}`);\n\t\t\treturn {};\n\t\t}\n\n\t\tconst [, type, widthStr, depthStr] = match;\n\t\tconst width = parseInt(widthStr, 10);\n\t\tconst depth = parseInt(depthStr, 10);\n\n\t\treturn {type: type as ConfigTypeEnum, width, depth};\n\t}\n}\n\ninterface ShelfDetails {\n\ttype?: ConfigTypeEnum;\n\twidth?: number;\n\tdepth?: number;\n}\n","import {Injectable} from '@angular/core';\nimport {Observable, Subject} from 'rxjs';\nimport {HttpClient, HttpParams} from '@angular/common/http';\nimport {environment} from '../../../environments/environment';\nimport {PriceConfig} from '../models/price-config.interface';\nimport {PriceConfigType} from '../models/price-config-types.interface';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class PriceConfigurationService {\n\tbaseUrl: string = `${environment.url}/core/price-config`;\n\tpriceConfigSubject: Subject = new Subject();\n\n\tconstructor(private http: HttpClient) {}\n\n\tfindAll(): Observable {\n\t\treturn this.http.get(`${this.baseUrl}`);\n\t}\n\n\tfindAllPriceConfigTypes(): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/types`);\n\t}\n\n\tfindPriceConfigsByType(type: string, date?: string): Observable {\n\t\tlet params: HttpParams = new HttpParams();\n\n\t\tif (date) {\n\t\t\tparams = params.append('date', date);\n\t\t}\n\n\t\treturn this.http.get(`${this.baseUrl}/type/${type}`, {params});\n\t}\n\n\tfindAllPriceConfigCodeTypes(): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/code`);\n\t}\n\n\tfindOne(id: number): Observable {\n\t\treturn this.http.get(`${this.baseUrl}${id}`);\n\t}\n\tupdate(id: number, priceConfig: Partial): Observable {\n\t\treturn this.http.patch(`${this.baseUrl}/${id}`, priceConfig);\n\t}\n\tcreate(priceConfig: Partial): Observable {\n\t\treturn this.http.post(`${this.baseUrl}`, priceConfig);\n\t}\n\n remove(id: number): Observable {\n return this.http.delete(`${this.baseUrl}/${id}`);\n }\n}\n","import {HttpClient} from '@angular/common/http';\nimport {BehaviorSubject, Observable} from 'rxjs';\nimport {PriceLevel} from '../models/price-level.interface';\nimport {environment} from '../../../environments/environment';\nimport {Injectable} from '@angular/core';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class PriceLevelService {\n\tprivate priceLevelDataSource = new BehaviorSubject([]);\n\treadonly priceLevels = this.priceLevelDataSource.asObservable();\n\n\tconstructor(private http: HttpClient) {\n\t\tthis.findAll();\n\t}\n\n\tfindAll(): void {\n\t\tthis.http\n\t\t\t.get(`${environment.url}/core/price-level`)\n\t\t\t.subscribe((priceLevels) => this.priceLevelDataSource.next(priceLevels));\n\t}\n\n\tcreate(priceLevel: PriceLevel): Observable {\n\t\treturn this.http.post(`${environment.url}/core/price-level`, priceLevel);\n\t}\n\n\tupdate(id: number | undefined, priceLevel: PriceLevel): Observable {\n\t\treturn this.http.put(`${environment.url}/core/price-level/${id}`, priceLevel);\n\t}\n}\n","import {Injectable} from '@angular/core';\nimport {HttpClient, HttpParams} from '@angular/common/http';\nimport {environment} from '../../../environments/environment';\nimport {Observable} from 'rxjs';\nimport {ProductionDayHourOverride} from '../models/production-day-hour-override.model';\nimport {ProductionHours} from '../models/production-hours.interface';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class ProductionDayHourService {\n\tbaseUrl: string = `${environment.url}/production-day-hours`;\n\n\tconstructor(private http: HttpClient) {}\n\n\tgetOverride(selectedDate: string): Observable {\n\t\tlet params = new HttpParams();\n\t\tparams = params.append('selectedDate', selectedDate);\n\t\treturn this.http.get(`${this.baseUrl}/overrides`, {params: params});\n\t}\n\n\tupdateOverride(selectedDate: string, overrides: ProductionDayHourOverride[]): Observable {\n\t\tlet params = new HttpParams();\n\t\tparams = params.append('selectedDate', selectedDate);\n\t\treturn this.http.post(`${this.baseUrl}/overrides`, overrides, {params: params});\n\t}\n}\n","import {Injectable} from '@angular/core';\nimport {environment} from '../../../environments/environment';\nimport {HttpClient} from '@angular/common/http';\nimport {ProjectDocument} from '../models/project-document.interface';\nimport {Observable, Subject} from 'rxjs';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class ProjectDocumentService {\n\tbaseUrl: string = `${environment.url}/project`;\n\tsurveyFileSubject = new Subject();\n\tsurveyDtoSubject = new Subject();\n\tsurveyFileRemoveSubject = new Subject();\n\tsurveyDtoRemoveSubject = new Subject();\n\tsurveyFileUploadedSubject = new Subject();\n\tconstructor(private http: HttpClient) {}\n\n\tcreate(formData: FormData, id: number): Observable {\n\t\treturn this.http.post(`${this.baseUrl}/${id}/documents`, formData);\n\t}\n\n\tfindOne(id: number, documentName: string): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/${id}/documents/${documentName}`);\n\t}\n\n\tdelete(id: number): Promise {\n\t\treturn new Promise((resolve) => {\n\t\t\tthis.http.delete(`${this.baseUrl}/documents/${id}`).subscribe(() => {\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tarchive(id: number, ids: (number | undefined)[]): Observable {\n\t\treturn this.http.post(`${this.baseUrl}/${id}/documents/archive`, ids);\n\t}\n}\n","import {Injectable} from '@angular/core';\nimport {BehaviorSubject, Observable} from 'rxjs';\nimport {HttpClient, HttpParams} from '@angular/common/http';\nimport {environment} from '../../../environments/environment';\nimport {Project, ProjectUpdate} from '../models/project.interface';\nimport {MatSnackBar} from '@angular/material/snack-bar';\nimport {SnackbarActionEnum} from '../enums/snackbar-action.enum';\nimport {ProjectTask} from '../models/project-task.model';\nimport {ProjectSchedule, ProjectScheduleUpdate} from '../models/project-schedule.interface';\nimport {ProjectActivity} from '../models/project-activity.interface';\nimport {QuoteHeader} from '../models/quote-header.interface';\nimport {ProjectEstimate} from '../models/project-estimate.interface';\nimport {ProjectInstall} from '../models/project-install.interface';\nimport {Quote} from '../models/quote.interface';\nimport {Router} from '@angular/router';\nimport {ProjectInstallShip, UpdateProjectInstallShip} from '../models/project-install-ship.interface';\n\n@Injectable({\n\tprovidedIn: 'root'\n})\nexport class ProjectsService {\n\tbaseUrl: string = `${environment.url}/project`;\n\n\tprivate projectsDataSource: BehaviorSubject = new BehaviorSubject([]);\n\treadonly projects: Observable = this.projectsDataSource.asObservable();\n\n\tpublic projectDataSource: BehaviorSubject = new BehaviorSubject(null);\n\treadonly project: Observable = this.projectDataSource.asObservable();\n\n private loadingSubject: BehaviorSubject = new BehaviorSubject(false);\n loading$ = this.loadingSubject.asObservable();\n\n\tprivate dateRangeOptions: any[] = [];\n\n\tconstructor(private http: HttpClient, private snackbar: MatSnackBar, private router: Router) {\n\t\tthis.createDateRangeOptions();\n\t}\n\n\tfindAllActive(): void {\n\t\tthis.http.get(this.baseUrl).subscribe((projects: Project[]) => {\n\t\t\tthis.projectsDataSource.next(projects);\n\t\t});\n\t}\n\n\tfindAllInactive(): void {\n\t\tthis.http.get(`${this.baseUrl}/inactive`).subscribe((projects: Project[]) => {\n\t\t\tthis.projectsDataSource.next(projects);\n\t\t});\n\t}\n\n isProjectActive(id: number): Observable {\n return this.http.get(`${this.baseUrl}/${id}/active`);\n }\n\n\tfindAllChangeRequestDocumentsByQuote(projectId: number): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/${projectId}/quote-documents`);\n\t}\n\n\tfindQuotesAssociatedWithProject(id: number): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/${id}/quotes`);\n\t}\n\n\tfindOne(id: number): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/${id}`);\n\t}\n\n\tfindByOrder(id: string): Observable {\n\t\treturn this.http.get(`${this.baseUrl}/order/${id}`);\n\t}\n\n\tclearProject(): void {\n\t\tthis.projectDataSource.next(null);\n\t}\n\n\tsetProject(id: number) {\n\t\tthis.http.get(`${this.baseUrl}/${id}`).subscribe((response) => {\n\t\t\tthis.projectDataSource.next(response);\n\t\t});\n\t}\n\n\tupdate(project: ProjectUpdate, rfqStatusChange: boolean, returnToProjects: boolean, showSnackbarMessage?: string) {\n this.loadingSubject.next(true);\n\t\tif (project.installDate) {\n\t\t\t// @ts-ignore\n\t\t\tproject.installDate = new Date(project.installDate).toISOString().substring(0, 10);\n\t\t}\n\n\t\tif (project.estimateDate && Object.keys(project.estimateDate).length > 0) {\n\t\t\t// @ts-ignore\n\t\t\tproject.estimateDate = new Date(project.estimateDate).toISOString().substring(0, 10);\n\t\t}\n\t\tconst params = new HttpParams().set('rfqStatusChange', rfqStatusChange.toString());\n\t\tthis.http.put(`${this.baseUrl}/${project.id}`, project, {params}).subscribe(\n\t\t\t(updateProject) => {\n\t\t\t\t{\n\t\t\t\t\t//Update the projects with the newly updated project\n\t\t\t\t\tconst projects: Project[] = this.projectsDataSource.getValue();\n\t\t\t\t\tlet projectToUpdate: number = projects.findIndex((project: Project) => {\n\t\t\t\t\t\treturn project.id === updateProject.id;\n\t\t\t\t\t});\n\t\t\t\t\tif (projectToUpdate !== -1) {\n\t\t\t\t\t\t//Merge original and updated project to maintain any UI set fields\n\t\t\t\t\t\tprojects[projectToUpdate] = {...projects[projectToUpdate], ...updateProject};\n\t\t\t\t\t\tthis.projectsDataSource.next(projects);\n\t\t\t\t\t}\n\t\t\t\t\tthis.projectDataSource.next(updateProject);\n\t\t\t\t\tthis.snackbar.open(showSnackbarMessage ? showSnackbarMessage : 'Project Updated', SnackbarActionEnum.SUCCESS);\n\t\t\t\t\tif (returnToProjects) this.router.navigate(['/projects']);\n\t\t\t\t}\n\t\t\t},\n\t\t\t(error): void => {\n\t\t\t\tconsole.error(error);\n\t\t\t\tthis.snackbar.open('Error Updating Project', SnackbarActionEnum.ERROR);\n\t\t\t},\n () => this.loadingSubject.next(false)\n\t\t);\n\t}\n\n\tupdateOnly(project: ProjectUpdate): Observable