diff --git a/src/features/need/need.controller.ts b/src/features/need/need.controller.ts index 3af4f46a6..55f209f62 100644 --- a/src/features/need/need.controller.ts +++ b/src/features/need/need.controller.ts @@ -192,9 +192,52 @@ export class NeedController { const socialWorker = await this.userService.getFlaskSocialWorker( socialWorkerId, ); // sw ngo - return await this.needService.getNotConfirmedNeeds(socialWorkerId, null, [ - socialWorker.ngo_id, - ]); + const unconfirmedCount = await this.needService.getNotConfirmedNeeds( + socialWorkerId, + null, + [socialWorker.ngo_id], + ); + return unconfirmedCount[1]; + } + + @Get(`auto/confirm`) + @ApiOperation({ description: 'Auto confirm needs' }) + async autoConfirmedNeeds(@Req() req: Request) { + const panelFlaskUserId = req.headers['panelFlaskUserId']; + const panelFlaskTypeId = req.headers['panelFlaskTypeId']; + + if (!isAuthenticated(panelFlaskUserId, panelFlaskTypeId)) { + throw new ForbiddenException(401, 'You Are not authorized!'); + } + + const swIds = await this.userService + .getFlaskSwIds() + .then((r) => r.map((s) => s.id)); + + const ngoIds = await this.ngoService + .getFlaskNgos() + .then((r) => r.map((s) => s.id)); + + const toBeConfirmed = config().dataCache.fetchToBeConfirmed(); + if (!toBeConfirmed || !toBeConfirmed[0]) { + const notConfirmed = await this.needService.getNotConfirmedNeeds( + null, + swIds, + ngoIds, + ); + + for await (const need of notConfirmed[0]) { + const duplicates = await this.needService.getDuplicateNeeds( + need.child_id, + need.id, + ); + toBeConfirmed.push({ need, duplicates }); + } + + config().dataCache.storeToBeConfirmed(toBeConfirmed); + } + + return toBeConfirmed; } @Get('duplicates/:flaskChildId/:flaskNeedId') @@ -287,14 +330,6 @@ export class NeedController { throw new ForbiddenException('You Are not the Super admin'); } - const swIds = await this.userService - .getFlaskSwIds() - .then((r) => r.map((s) => s.id)); // all ngos - - const ngoIds = await this.ngoService - .getFlaskNgos() - .then((r) => r.map((s) => s.id)); - const needs = await this.needService.getArrivalUpdateCandidates(); const token = diff --git a/src/features/need/need.service.ts b/src/features/need/need.service.ts index 8eeb33552..ebe18ab26 100644 --- a/src/features/need/need.service.ts +++ b/src/features/need/need.service.ts @@ -343,7 +343,7 @@ export class NeedService { socialWorker: number, swIds: number[], ngoIds: number[], - ): Promise { + ): Promise<[Need[], number]> { const queryBuilder = this.flaskNeedRepository .createQueryBuilder('need') .leftJoinAndMapOne( @@ -367,45 +367,31 @@ export class NeedService { statusNotPaid: PaymentStatusEnum.NOT_PAID, }) .select([ - 'child', + 'child.sayname_translations', 'ngo.id', 'ngo.name', - 'ngo.logoUrl', 'need.id', 'need.child_id', 'need.created_by_id', 'need.name_translations', + 'need.description_translations', 'need.title', 'need.imageUrl', 'need.category', 'need.type', - 'need.isUrgent', 'need.link', - 'need.affiliateLinkUrl', - 'need.bank_track_id', - 'need.doing_duration', 'need.status', 'need.img', - 'need.purchase_cost', 'need._cost', - 'need.isConfirmed', + 'need.isDeleted', 'need.created', - 'need.updated', 'need.confirmDate', - 'need.confirmUser', - 'need.doneAt', - 'need.ngo_delivery_date', - 'need.child_delivery_date', - 'need.purchase_date', - 'need.expected_delivery_date', - 'need.unavailable_from', ]) .cache(60000) .orderBy('need.created', 'ASC'); - const accurateCount = await queryBuilder.getCount(); - - return accurateCount; + return await queryBuilder.getManyAndCount(); } + async getNotPaidNeeds( options: PaginateQuery, socialWorker: number, @@ -734,6 +720,7 @@ export class NeedService { // .andWhere('child.id_ngo IN (:...ngoIds)', { ngoIds: ngoIds }) // e.g: sw: 1 used to be in Ngo:13, therefore some needs are created in an ngo where their sw is now active somewhere else. // .andWhere('need_receipt.deleted = :receiptDeleted', { receiptDeleted: null }) .andWhere('need.isDeleted = :needDeleted', { needDeleted: false }) + // .andWhere('need._cost = :price', { price: 0 }) // only for test purposes .andWhere( new Brackets((qb) => { qb.where('need.type = :typeProduct', { @@ -803,6 +790,12 @@ export class NeedService { const need = await this.getFlaskNeed(needId); const queryBuilder = this.flaskNeedRepository .createQueryBuilder('need') + .leftJoinAndMapOne( + 'need.child', + Child, + 'child', + 'child.id = need.child_id', + ) // .where("need.unavailable_from > :startDate", { startDate: new Date(2021, 2, 3) }) // .andWhere("need.unavailable_from < :endDate", { endDate: new Date(2023, 1, 3) }) .andWhere('need.child_id = :childId', { childId: childId }) @@ -817,27 +810,24 @@ export class NeedService { statusPaid: PaymentStatusEnum.COMPLETE_PAY, }) .select([ + 'child.sayname_translations', 'need.id', 'need.title', 'need.imageUrl', 'need.child_id', 'need.name_translations', + 'need.description_translations', 'need.title', + 'need._cost', 'need.type', 'need.link', 'need.status', + 'need.category', 'need.isConfirmed', - 'need.doing_duration', - 'need.status', 'need.created', 'need.updated', 'need.confirmDate', - 'need.doneAt', - 'need.ngo_delivery_date', - 'need.child_delivery_date', - 'need.purchase_date', - 'need.expected_delivery_date', - 'need.unavailable_from', + 'need.created', ]) .cache(60000) .orderBy('need.created', 'ASC'); diff --git a/src/features/schedule/schedule.module.ts b/src/features/schedule/schedule.module.ts index 700081ee1..7423eba82 100644 --- a/src/features/schedule/schedule.module.ts +++ b/src/features/schedule/schedule.module.ts @@ -17,6 +17,11 @@ import { VariableEntity } from 'src/entities/variable.entity'; import { AllUserEntity } from 'src/entities/user.entity'; import { Receipt } from 'src/entities/flaskEntities/receipt.entity'; import { NeedReceipt } from 'src/entities/flaskEntities/needReceipt.entity'; +import { NgoService } from '../ngo/ngo.service'; +import { UserService } from '../user/user.service'; +import { NgoArrivalEntity, NgoEntity } from 'src/entities/ngo.entity'; +import { ContributorEntity } from 'src/entities/contributor.entity'; +import { EthereumAccountEntity } from 'src/entities/ethereum.account.entity'; @Module({ imports: [ @@ -39,10 +44,21 @@ import { NeedReceipt } from 'src/entities/flaskEntities/needReceipt.entity'; NeedEntity, VariableEntity, PaymentEntity, + NgoEntity, + NgoArrivalEntity, + ContributorEntity, AllUserEntity, + EthereumAccountEntity ]), ], controllers: [], - providers: [ScheduleService, NeedService, FamilyService, AnalyticService], + providers: [ + ScheduleService, + NeedService, + FamilyService, + AnalyticService, + NgoService, + UserService, + ], }) export class ScheduleTaskModule {} diff --git a/src/utils/dataCache.ts b/src/utils/dataCache.ts index 440b849ac..cf186f980 100644 --- a/src/utils/dataCache.ts +++ b/src/utils/dataCache.ts @@ -18,6 +18,7 @@ export default class DataCache { childActiveFamilies = null; medianList = []; midjourneyList = []; + ToBeConfirmedList = []; countChildrenNoNeeds = null; updateChildrenNoNeeds(count: number) { @@ -81,6 +82,10 @@ export default class DataCache { list.forEach((e) => this.midjourneyList.push(e)); }; + storeToBeConfirmed = (list: any[]) => { + this.ToBeConfirmedList = list; + }; + // dApp user ratio in different roles / distance ratio storeFamilyData = ({ fathersData, @@ -123,7 +128,8 @@ export default class DataCache { }; }; - fetchMidjourney = () => (this.midjourneyList = this.midjourneyList); + fetchMidjourney = () => this.midjourneyList; + fetchToBeConfirmed = () => this.ToBeConfirmedList; fetchChildrenNoNeeds() { return this.countChildrenNoNeeds; } diff --git a/src/utils/needConfirm.ts b/src/utils/needConfirm.ts new file mode 100644 index 000000000..6df8dc456 --- /dev/null +++ b/src/utils/needConfirm.ts @@ -0,0 +1,129 @@ +import { Need } from 'src/entities/flaskEntities/need.entity'; +import { ServerError } from 'src/filters/server-exception.filter'; +import { + NeedTypeEnum, + PaymentStatusEnum, +} from 'src/types/interfaces/interface'; + +export function checkNeed(need: Need, duplicates: Need[]) { + const category = need.category; + const type = need.type; + const status = need.status; + const retailerLink = need.link; + const price = need._cost; + const icon = need.imageUrl; + const title = need.imageUrl; + const name_en = need.name_translations.en; + const description_en = need.description_translations.en; + const confirmDate = need.confirmDate; + const isDeleted = need.isDeleted; + + if (!title || !icon || !price || !name_en || !description_en) { + throw new ServerError( + 'We need title, icon, price, name and description!', + 500, + ); + } + + if (isDeleted || confirmDate) { + throw new ServerError("This need's is not available to confirm!", 502); + } + + if (status > PaymentStatusEnum.NOT_PAID) { + throw new ServerError("This need's status is wrong!", 503); + } + + if (type === NeedTypeEnum.PRODUCT && !retailerLink) { + throw new ServerError('We need the link!', 504); + } + + if (duplicates.length > 0) { + const dupList = []; + for (let i = 0; i < duplicates.length; i++) { + let C: boolean; // category + let T: boolean; // type + let S: boolean; // status + let R: boolean; // retailerLink + let P: boolean; // price + let I: boolean; // icon + let TT: boolean; // title + let N: boolean; // name_en + let D: boolean; // description_en + let CO: boolean; // confirmDate + let IS: boolean; // isDeleted + + if (category === duplicates[i].category) { + C = true; + } else { + C = false; + } + if (type === duplicates[i].type) { + T = true; + } else { + T = false; + } + if (status === duplicates[i].status) { + S = true; + } else { + S = false; + } + if (retailerLink === duplicates[i].link) { + R = true; + } else { + R = false; + } + if (price === duplicates[i]._cost) { + P = true; + } else { + P = false; + } + if (icon === duplicates[i].imageUrl) { + I = true; + } else { + I = false; + } + if (title === duplicates[i].title) { + TT = true; + } else { + TT = false; + } + if (name_en === duplicates[i].name_translations.en) { + N = true; + } else { + N = false; + } + if (description_en === duplicates[i].description_translations.en) { + D = true; + } else { + D = false; + } + if (confirmDate === duplicates[i].confirmDate) { + CO = true; + } else { + CO = false; + } + if (isDeleted === duplicates[i].isDeleted) { + IS = true; + } else { + IS = false; + } + + const duplicateNeed = { + id: duplicates[i], + C, + T, + S, + R, + P, + I, + TT, + N, + D, + CO, + IS, + }; + dupList.push(duplicateNeed); + } + } else { + } +}