.
This commit is contained in:
parent
b6721c1b56
commit
ebb2d06903
@ -63,6 +63,7 @@
|
|||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"express-openapi-validator": "^5.0.4",
|
"express-openapi-validator": "^5.0.4",
|
||||||
|
"handlebars": "^4.7.8",
|
||||||
"helmet": "^7.0.0",
|
"helmet": "^7.0.0",
|
||||||
"http-status": "^1.7.4",
|
"http-status": "^1.7.4",
|
||||||
"joi": "^17.12.3",
|
"joi": "^17.12.3",
|
||||||
@ -77,6 +78,7 @@
|
|||||||
"passport-jwt": "^4.0.1",
|
"passport-jwt": "^4.0.1",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
|
"puppeteer": "^22.13.1",
|
||||||
"remove": "^0.1.5",
|
"remove": "^0.1.5",
|
||||||
"response-time": "^2.3.2",
|
"response-time": "^2.3.2",
|
||||||
"sequelize": "^6.37.3",
|
"sequelize": "^6.37.3",
|
||||||
|
|||||||
@ -57,10 +57,14 @@ export abstract class ExpressController implements IController {
|
|||||||
return this.res.status(httpStatus.NO_CONTENT).send();
|
return this.res.status(httpStatus.NO_CONTENT).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
public download(filepath: string, filename: string, done?: any) {
|
public downloadFile(filepath: string, filename: string, done?: any) {
|
||||||
return this.res.download(filepath, filename, done);
|
return this.res.download(filepath, filename, done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public downloadPDF(pdfBuffer: Buffer, filename: string) {
|
||||||
|
return this._download(pdfBuffer, "application/pdf", `${filename}.pdf`);
|
||||||
|
}
|
||||||
|
|
||||||
public clientError(message?: string) {
|
public clientError(message?: string) {
|
||||||
return this._errorResponse(httpStatus.BAD_REQUEST, message);
|
return this._errorResponse(httpStatus.BAD_REQUEST, message);
|
||||||
}
|
}
|
||||||
@ -116,4 +120,14 @@ export abstract class ExpressController implements IController {
|
|||||||
): express.Response<IError_Response_DTO> {
|
): express.Response<IError_Response_DTO> {
|
||||||
return generateExpressError(this.req, this.res, statusCode, message, error);
|
return generateExpressError(this.req, this.res, statusCode, message, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _download(buffer: Buffer, contentType: string, filename: string) {
|
||||||
|
this.res.set({
|
||||||
|
"Content-Type": contentType,
|
||||||
|
"Content-Disposition": `attachment; filename=${filename}`,
|
||||||
|
"Content-Length": buffer.length,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.res.send(buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import {
|
|||||||
import { IRepositoryManager } from "@/contexts/common/domain";
|
import { IRepositoryManager } from "@/contexts/common/domain";
|
||||||
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
||||||
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
||||||
import { DomainError, IUpdateProfile_Request_DTO, Result, UniqueID } from "@shared/contexts";
|
import { IUpdateProfile_Request_DTO, Note, Result, UniqueID } from "@shared/contexts";
|
||||||
import { IProfileRepository, Profile } from "../domain";
|
import { IProfileRepository, Profile } from "../domain";
|
||||||
|
|
||||||
export interface IUpdateProfileUseCaseRequest extends IUseCaseRequest {
|
export interface IUpdateProfileUseCaseRequest extends IUseCaseRequest {
|
||||||
@ -32,7 +32,6 @@ export class UpdateProfileUseCase
|
|||||||
|
|
||||||
async execute(request: IUpdateProfileUseCaseRequest): Promise<UpdateProfileResponseOrError> {
|
async execute(request: IUpdateProfileUseCaseRequest): Promise<UpdateProfileResponseOrError> {
|
||||||
const { userId, profileDTO } = request;
|
const { userId, profileDTO } = request;
|
||||||
const profileRepository = this._getProfileRepository();
|
|
||||||
|
|
||||||
// Comprobar que existe el profile
|
// Comprobar que existe el profile
|
||||||
const exitsOrError = await this._getProfileDealer(userId);
|
const exitsOrError = await this._getProfileDealer(userId);
|
||||||
@ -45,43 +44,17 @@ export class UpdateProfileUseCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const oldProfile = exitsOrError.object;
|
const profile = exitsOrError.object;
|
||||||
|
|
||||||
// Crear perfil con datos actualizados
|
// Actualizar el perfil con datos actualizados
|
||||||
const profileOrError = Profile.create(
|
profile.contactInformation = Note.create(profileDTO.contact_information).object;
|
||||||
{
|
profile.defaultPaymentMethod = Note.create(profileDTO.default_payment_method).object;
|
||||||
contactInformation: profileDTO.contact_information,
|
profile.defaultLegalTerms = Note.create(profileDTO.default_legal_terms).object;
|
||||||
defaultPaymentMethod: profileDTO.default_payment_method,
|
profile.defaultNotes = Note.create(profileDTO.default_notes).object;
|
||||||
defaultLegalTerms: profileDTO.default_legal_terms,
|
profile.defaultQuoteValidity = Note.create(profileDTO.default_quote_validity).object;
|
||||||
defaultNotes: profileDTO.default_notes,
|
|
||||||
defaultQuoteValidity: profileDTO.default_quote_validity,
|
|
||||||
},
|
|
||||||
oldProfile.id
|
|
||||||
);
|
|
||||||
|
|
||||||
if (profileOrError.isFailure) {
|
|
||||||
const { error: domainError } = profileOrError;
|
|
||||||
let errorCode = "";
|
|
||||||
let message = "";
|
|
||||||
|
|
||||||
switch (domainError.code) {
|
|
||||||
// Errores manuales
|
|
||||||
case DomainError.INVALID_INPUT_DATA:
|
|
||||||
errorCode = UseCaseError.INVALID_INPUT_DATA;
|
|
||||||
message = "The profile has some incorrect data";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
errorCode = UseCaseError.UNEXCEPTED_ERROR;
|
|
||||||
message = domainError.message;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.fail(UseCaseError.create(errorCode, message, domainError));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guardar los cambios
|
// Guardar los cambios
|
||||||
return this._saveProfile(profileOrError.object);
|
return this._saveProfile(profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _saveProfile(updatedProfile: Profile) {
|
private async _saveProfile(updatedProfile: Profile) {
|
||||||
|
|||||||
@ -63,19 +63,39 @@ export class Profile extends AggregateRoot<IProfileProps> implements IProfile {
|
|||||||
return this.props.contactInformation;
|
return this.props.contactInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set contactInformation(newNote: Note) {
|
||||||
|
this.props.contactInformation = newNote;
|
||||||
|
}
|
||||||
|
|
||||||
get defaultPaymentMethod(): Note {
|
get defaultPaymentMethod(): Note {
|
||||||
return this.props.defaultPaymentMethod;
|
return this.props.defaultPaymentMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set defaultPaymentMethod(newPaymentMethod: Note) {
|
||||||
|
this.props.defaultPaymentMethod = newPaymentMethod;
|
||||||
|
}
|
||||||
|
|
||||||
get defaultNotes(): Note {
|
get defaultNotes(): Note {
|
||||||
return this.props.defaultNotes;
|
return this.props.defaultNotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set defaultNotes(newDefaultNotes: Note) {
|
||||||
|
this.props.defaultNotes = newDefaultNotes;
|
||||||
|
}
|
||||||
|
|
||||||
get defaultLegalTerms(): Note {
|
get defaultLegalTerms(): Note {
|
||||||
return this.props.defaultLegalTerms;
|
return this.props.defaultLegalTerms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set defaultLegalTerms(newDefaultLegalTerms: Note) {
|
||||||
|
this.props.defaultLegalTerms = newDefaultLegalTerms;
|
||||||
|
}
|
||||||
|
|
||||||
get defaultQuoteValidity(): Note {
|
get defaultQuoteValidity(): Note {
|
||||||
return this.props.defaultQuoteValidity;
|
return this.props.defaultQuoteValidity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set defaultQuoteValidity(newDefaultQuoteValidity: Note) {
|
||||||
|
this.props.defaultQuoteValidity = newDefaultQuoteValidity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
export * from "./Profile.context";
|
|
||||||
export * from "./express";
|
export * from "./express";
|
||||||
|
export * from "./Profile.context";
|
||||||
|
|||||||
@ -118,11 +118,16 @@ export class CreateDealerUseCase
|
|||||||
return Result.fail(nameOrError.error);
|
return Result.fail(nameOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const languageOrError = Language.createFromCode(dealerDTO.lang_code);
|
||||||
|
if (languageOrError.isFailure) {
|
||||||
|
return Result.fail(languageOrError.error);
|
||||||
|
}
|
||||||
|
|
||||||
return Dealer.create(
|
return Dealer.create(
|
||||||
{
|
{
|
||||||
name: nameOrError.object,
|
name: nameOrError.object,
|
||||||
currency: CurrencyData.createDefaultCode().object,
|
currency: CurrencyData.createDefaultCode().object,
|
||||||
language: Language.createDefaultCode().object,
|
language: languageOrError.object,
|
||||||
status: DealerStatus.createActive(),
|
status: DealerStatus.createActive(),
|
||||||
//user_id: user
|
//user_id: user
|
||||||
},
|
},
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { IRepositoryManager } from "@/contexts/common/domain";
|
|||||||
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
||||||
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
||||||
import {
|
import {
|
||||||
|
CurrencyData,
|
||||||
DomainError,
|
DomainError,
|
||||||
IDomainError,
|
IDomainError,
|
||||||
IUpdateDealer_Request_DTO,
|
IUpdateDealer_Request_DTO,
|
||||||
@ -109,15 +110,28 @@ export class UpdateDealerUseCase
|
|||||||
return Result.fail(nameOrError.error);
|
return Result.fail(nameOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const languageOrError = Language.createFromCode(dealerDTO.language);
|
const languageOrError = Language.createFromCode(dealerDTO.lang_code);
|
||||||
if (languageOrError.isFailure) {
|
if (languageOrError.isFailure) {
|
||||||
return Result.fail(languageOrError.error);
|
return Result.fail(languageOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currencyOrError = CurrencyData.createDefaultCode();
|
||||||
|
if (currencyOrError.isFailure) {
|
||||||
|
return Result.fail(currencyOrError.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const DealerStatusOrError = CurrencyData.createDefaultCode();
|
||||||
|
if (currencyOrError.isFailure) {
|
||||||
|
return Result.fail(currencyOrError.error);
|
||||||
|
}
|
||||||
|
|
||||||
return Dealer.create(
|
return Dealer.create(
|
||||||
{
|
{
|
||||||
name: nameOrError.object,
|
name: nameOrError.object,
|
||||||
logo: "",
|
currency: currencyOrError.object,
|
||||||
|
//status:
|
||||||
|
|
||||||
|
//logo: "",
|
||||||
language: languageOrError.object,
|
language: languageOrError.object,
|
||||||
|
|
||||||
additionalInfo: KeyValueMap.create([
|
additionalInfo: KeyValueMap.create([
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
export * from "./CreateDealer.useCase";
|
//export * from "./CreateDealer.useCase";
|
||||||
export * from "./DeleteDealer.useCase";
|
//export * from "./DeleteDealer.useCase";
|
||||||
export * from "./GetDealer.useCase";
|
export * from "./GetDealer.useCase";
|
||||||
export * from "./GetDealerByUser.useCase";
|
export * from "./GetDealerByUser.useCase";
|
||||||
export * from "./ListDealers.useCase";
|
export * from "./ListDealers.useCase";
|
||||||
export * from "./UpdateDealer.useCase";
|
//export * from "./UpdateDealer.useCase";
|
||||||
|
|
||||||
export * from "./dealerServices";
|
export * from "./dealerServices";
|
||||||
|
|||||||
@ -1,77 +0,0 @@
|
|||||||
import {
|
|
||||||
IUseCase,
|
|
||||||
IUseCaseError,
|
|
||||||
IUseCaseRequest,
|
|
||||||
UseCaseError,
|
|
||||||
} from "@/contexts/common/application/useCases";
|
|
||||||
import { IRepositoryManager } from "@/contexts/common/domain";
|
|
||||||
import { ISequelizeAdapter } from "@/contexts/common/infrastructure/sequelize";
|
|
||||||
import { Result, UniqueID } from "@shared/contexts";
|
|
||||||
import { IQuoteRepository } from "../../domain";
|
|
||||||
|
|
||||||
import { IInfrastructureError } from "@/contexts/common/infrastructure";
|
|
||||||
import { Quote } from "../../domain/entities/Quotes/Quote";
|
|
||||||
|
|
||||||
export interface IGetQuoteByUserByUserUseCaseRequest extends IUseCaseRequest {
|
|
||||||
userId: UniqueID;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GetQuoteByUserResponseOrError =
|
|
||||||
| Result<never, IUseCaseError> // Misc errors (value objects)
|
|
||||||
| Result<Quote, never>; // Success!
|
|
||||||
|
|
||||||
export class GetQuoteByUserUseCase
|
|
||||||
implements IUseCase<IGetQuoteByUserByUserUseCaseRequest, Promise<GetQuoteByUserResponseOrError>>
|
|
||||||
{
|
|
||||||
private _adapter: ISequelizeAdapter;
|
|
||||||
private _repositoryManager: IRepositoryManager;
|
|
||||||
|
|
||||||
constructor(props: { adapter: ISequelizeAdapter; repositoryManager: IRepositoryManager }) {
|
|
||||||
this._adapter = props.adapter;
|
|
||||||
this._repositoryManager = props.repositoryManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getRepositoryByName<T>(name: string) {
|
|
||||||
return this._repositoryManager.getRepository<T>(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
request: IGetQuoteByUserByUserUseCaseRequest
|
|
||||||
): Promise<GetQuoteByUserResponseOrError> {
|
|
||||||
const { userId } = request;
|
|
||||||
|
|
||||||
// Validación de datos
|
|
||||||
// No hay en este caso
|
|
||||||
|
|
||||||
return await this.getUserQuote(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getUserQuote(userId: UniqueID) {
|
|
||||||
const transaction = this._adapter.startTransaction();
|
|
||||||
const QuoteRepoBuilder = this.getRepositoryByName<IQuoteRepository>("Quote");
|
|
||||||
|
|
||||||
let Quote: Quote | null = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await transaction.complete(async (t) => {
|
|
||||||
const QuoteRepo = QuoteRepoBuilder({ transaction: t });
|
|
||||||
Quote = await QuoteRepo.getByUserId(userId);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!Quote) {
|
|
||||||
return Result.fail(UseCaseError.create(UseCaseError.NOT_FOUND_ERROR, "Quote not found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.ok<Quote>(Quote!);
|
|
||||||
} catch (error: unknown) {
|
|
||||||
const _error = error as IInfrastructureError;
|
|
||||||
return Result.fail(
|
|
||||||
UseCaseError.create(
|
|
||||||
UseCaseError.REPOSITORY_ERROR,
|
|
||||||
"Error al consultar la cotización",
|
|
||||||
_error
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +1,5 @@
|
|||||||
export * from "./CreateQuote.useCase";
|
export * from "./CreateQuote.useCase";
|
||||||
export * from "./DeleteQuote.useCase";
|
export * from "./DeleteQuote.useCase";
|
||||||
export * from "./GetQuote.useCase";
|
export * from "./GetQuote.useCase";
|
||||||
export * from "./GetQuoteByUser.useCase";
|
|
||||||
export * from "./ListQuotes.useCase";
|
export * from "./ListQuotes.useCase";
|
||||||
export * from "./UpdateQuote.useCase";
|
export * from "./UpdateQuote.useCase";
|
||||||
|
|||||||
@ -12,6 +12,7 @@ export const GetDealerByUserPresenter: IGetDealerByUserPresenter = {
|
|||||||
return {
|
return {
|
||||||
id: dealer.id.toString(),
|
id: dealer.id.toString(),
|
||||||
name: dealer.name.toString(),
|
name: dealer.name.toString(),
|
||||||
|
lang_code: dealer.language.code,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export * from "./createDealer";
|
//export * from "./createDealer";
|
||||||
export * from "./deleteDealer";
|
//export * from "./deleteDealer";
|
||||||
export * from "./getDealer";
|
export * from "./getDealer";
|
||||||
export * from "./listDealers";
|
export * from "./listDealers";
|
||||||
export * from "./updateDealer";
|
//export * from "./updateDealer";
|
||||||
|
|||||||
@ -2,4 +2,5 @@ export * from "./createQuote";
|
|||||||
export * from "./deleteQuote";
|
export * from "./deleteQuote";
|
||||||
export * from "./getQuote";
|
export * from "./getQuote";
|
||||||
export * from "./listQuotes";
|
export * from "./listQuotes";
|
||||||
|
export * from "./reportQuote";
|
||||||
export * from "./updateQuote";
|
export * from "./updateQuote";
|
||||||
|
|||||||
@ -0,0 +1,97 @@
|
|||||||
|
import { IUseCaseError, UseCaseError } from "@/contexts/common/application/useCases";
|
||||||
|
import { ExpressController } from "@/contexts/common/infrastructure/express";
|
||||||
|
|
||||||
|
import { IServerError } from "@/contexts/common/domain/errors";
|
||||||
|
import { IInfrastructureError, InfrastructureError } from "@/contexts/common/infrastructure";
|
||||||
|
import { GetQuoteUseCase } from "@/contexts/sales/application";
|
||||||
|
import { Quote } from "@/contexts/sales/domain";
|
||||||
|
import { ensureIdIsValid } from "@shared/contexts";
|
||||||
|
import { ISalesContext } from "../../../../Sales.context";
|
||||||
|
import { IReportQuoteReporter } from "./reporter/ReportQuote.reporter";
|
||||||
|
|
||||||
|
export class ReportQuoteController extends ExpressController {
|
||||||
|
private useCase: GetQuoteUseCase;
|
||||||
|
private reporter: IReportQuoteReporter;
|
||||||
|
private context: ISalesContext;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
props: {
|
||||||
|
useCase: GetQuoteUseCase;
|
||||||
|
reporter: IReportQuoteReporter;
|
||||||
|
},
|
||||||
|
context: ISalesContext
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const { useCase, reporter: presenter } = props;
|
||||||
|
this.useCase = useCase;
|
||||||
|
this.reporter = presenter;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeImpl(): Promise<any> {
|
||||||
|
const { quoteId } = this.req.params;
|
||||||
|
|
||||||
|
// Validar ID
|
||||||
|
const quoteIdOrError = ensureIdIsValid(quoteId);
|
||||||
|
if (quoteIdOrError.isFailure) {
|
||||||
|
const errorMessage = "Quote ID is not valid";
|
||||||
|
const infraError = InfrastructureError.create(
|
||||||
|
InfrastructureError.INVALID_INPUT_DATA,
|
||||||
|
errorMessage,
|
||||||
|
quoteIdOrError.error
|
||||||
|
);
|
||||||
|
return this.invalidInputError(errorMessage, infraError);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await this.useCase.execute({
|
||||||
|
id: quoteIdOrError.object,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.isFailure) {
|
||||||
|
return this._handleExecuteError(result.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const quote = <Quote>result.object;
|
||||||
|
|
||||||
|
return this.downloadPDF(await this.reporter.toPDF(quote, this.context), "prueba.pdf");
|
||||||
|
} catch (e: unknown) {
|
||||||
|
return this.fail(e as IServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleExecuteError(error: IUseCaseError) {
|
||||||
|
let errorMessage: string;
|
||||||
|
let infraError: IInfrastructureError;
|
||||||
|
|
||||||
|
switch (error.code) {
|
||||||
|
case UseCaseError.NOT_FOUND_ERROR:
|
||||||
|
errorMessage = "Quote not found";
|
||||||
|
|
||||||
|
infraError = InfrastructureError.create(
|
||||||
|
InfrastructureError.RESOURCE_NOT_FOUND_ERROR,
|
||||||
|
errorMessage,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.notFoundError(errorMessage, infraError);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UseCaseError.UNEXCEPTED_ERROR:
|
||||||
|
errorMessage = error.message;
|
||||||
|
|
||||||
|
infraError = InfrastructureError.create(
|
||||||
|
InfrastructureError.UNEXCEPTED_ERROR,
|
||||||
|
errorMessage,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
return this.internalServerError(errorMessage, infraError);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
errorMessage = error.message;
|
||||||
|
return this.clientError(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
import { GetQuoteUseCase } from "@/contexts/sales/application";
|
||||||
|
import Express from "express";
|
||||||
|
import { registerQuoteRepository } from "../../../../Quote.repository";
|
||||||
|
import { ISalesContext } from "../../../../Sales.context";
|
||||||
|
import { ReportQuotePresenter } from "./reporter/ReportQuote.reporter";
|
||||||
|
import { ReportQuoteController } from "./ReportQuote.controller";
|
||||||
|
|
||||||
|
export const reportQuoteController = (
|
||||||
|
req: Express.Request,
|
||||||
|
res: Express.Response,
|
||||||
|
next: Express.NextFunction
|
||||||
|
) => {
|
||||||
|
const context: ISalesContext = res.locals.context;
|
||||||
|
|
||||||
|
registerQuoteRepository(context);
|
||||||
|
|
||||||
|
return new ReportQuoteController(
|
||||||
|
{
|
||||||
|
useCase: new GetQuoteUseCase(context),
|
||||||
|
reporter: ReportQuotePresenter,
|
||||||
|
},
|
||||||
|
context
|
||||||
|
).execute(req, res, next);
|
||||||
|
};
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import * as handlebars from "handlebars";
|
||||||
|
import * as puppeteer from "puppeteer";
|
||||||
|
import { Quote } from "../../../../../../domain";
|
||||||
|
import { ISalesContext } from "../../../../../Sales.context";
|
||||||
|
|
||||||
|
export interface IReportQuoteReporter {
|
||||||
|
toPDF: (quote: Quote, context: ISalesContext) => any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ReportQuotePresenter: IReportQuoteReporter = {
|
||||||
|
toPDF: async (quote: Quote, context: ISalesContext): Promise<Buffer> => {
|
||||||
|
// Obtener y compilar la plantilla HTML
|
||||||
|
const templateHtml = obtenerPlantillaHTML();
|
||||||
|
const template = handlebars.compile(templateHtml);
|
||||||
|
const html = template(quote);
|
||||||
|
|
||||||
|
// Generar el PDF con Puppeteer
|
||||||
|
const browser = await puppeteer.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.setContent(html);
|
||||||
|
const pdfBuffer = await page.pdf({ format: "A4" });
|
||||||
|
await browser.close();
|
||||||
|
|
||||||
|
return pdfBuffer;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const obtenerPlantillaHTML = (): string => {
|
||||||
|
// Implementar la lógica para obtener la plantilla HTML
|
||||||
|
return `
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Factura</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Factura: </h1>
|
||||||
|
<p>Cliente:</p>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
};
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./ReportQuote.reporter";
|
||||||
@ -1 +1 @@
|
|||||||
export * from "../../../../infrastructure/express/api/routes/sales.routes";
|
export * from "./controllers";
|
||||||
|
|||||||
@ -100,6 +100,8 @@ export const initializeSampleUser = async (
|
|||||||
await repository({ transaction: t }).create(user);
|
await repository({ transaction: t }).create(user);
|
||||||
console.log("Usuario creado");
|
console.log("Usuario creado");
|
||||||
return user;
|
return user;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
import { checkUser, checkisAdmin } from "@/contexts/auth";
|
import { checkUser, checkisAdmin } from "@/contexts/auth";
|
||||||
import {
|
import {
|
||||||
createDealerController,
|
|
||||||
deleteDealerController,
|
|
||||||
getDealerController,
|
getDealerController,
|
||||||
listDealersController,
|
listDealersController,
|
||||||
updateDealerController,
|
|
||||||
} from "@/contexts/sales/infrastructure/express/controllers/dealers";
|
} from "@/contexts/sales/infrastructure/express/controllers/dealers";
|
||||||
import { getDealerMiddleware } from "@/contexts/sales/infrastructure/express/middlewares/dealerMiddleware";
|
import { getDealerMiddleware } from "@/contexts/sales/infrastructure/express/middlewares/dealerMiddleware";
|
||||||
import Express from "express";
|
import Express from "express";
|
||||||
@ -14,9 +11,9 @@ export const DealerRouter = (appRouter: Express.Router) => {
|
|||||||
|
|
||||||
dealerRoutes.get("/", checkisAdmin, listDealersController);
|
dealerRoutes.get("/", checkisAdmin, listDealersController);
|
||||||
dealerRoutes.get("/:dealerId", checkUser, getDealerMiddleware, getDealerController);
|
dealerRoutes.get("/:dealerId", checkUser, getDealerMiddleware, getDealerController);
|
||||||
dealerRoutes.post("/", checkisAdmin, createDealerController);
|
///dealerRoutes.post("/", checkisAdmin, createDealerController);
|
||||||
dealerRoutes.put("/:dealerId", checkisAdmin, updateDealerController);
|
//dealerRoutes.put("/:dealerId", checkisAdmin, updateDealerController);
|
||||||
dealerRoutes.delete("/:dealerId", checkisAdmin, deleteDealerController);
|
//dealerRoutes.delete("/:dealerId", checkisAdmin, deleteDealerController);
|
||||||
|
|
||||||
// Anidar quotes en /dealers/:dealerId
|
// Anidar quotes en /dealers/:dealerId
|
||||||
//dealerRoutes.use("/:dealerId/quotes", quoteRoutes);
|
//dealerRoutes.use("/:dealerId/quotes", quoteRoutes);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import {
|
|||||||
createQuoteController,
|
createQuoteController,
|
||||||
getQuoteController,
|
getQuoteController,
|
||||||
listQuotesController,
|
listQuotesController,
|
||||||
|
reportQuoteController,
|
||||||
updateQuoteController,
|
updateQuoteController,
|
||||||
} from "@/contexts/sales/infrastructure/express/controllers";
|
} from "@/contexts/sales/infrastructure/express/controllers";
|
||||||
import { getDealerMiddleware } from "@/contexts/sales/infrastructure/express/middlewares/dealerMiddleware";
|
import { getDealerMiddleware } from "@/contexts/sales/infrastructure/express/middlewares/dealerMiddleware";
|
||||||
@ -11,12 +12,15 @@ import Express from "express";
|
|||||||
export const QuoteRouter = (appRouter: Express.Router) => {
|
export const QuoteRouter = (appRouter: Express.Router) => {
|
||||||
const quoteRoutes: Express.Router = Express.Router({ mergeParams: true });
|
const quoteRoutes: Express.Router = Express.Router({ mergeParams: true });
|
||||||
|
|
||||||
|
// Users CRUD
|
||||||
quoteRoutes.get("/", checkUser, getDealerMiddleware, listQuotesController);
|
quoteRoutes.get("/", checkUser, getDealerMiddleware, listQuotesController);
|
||||||
quoteRoutes.get("/:quoteId", checkUser, getDealerMiddleware, getQuoteController);
|
quoteRoutes.get("/:quoteId", checkUser, getDealerMiddleware, getQuoteController);
|
||||||
//quoteRoutes.get("/:quoteId/report", checkUser, getDealerMiddleware, getReportController;
|
|
||||||
quoteRoutes.post("/", checkUser, getDealerMiddleware, createQuoteController);
|
quoteRoutes.post("/", checkUser, getDealerMiddleware, createQuoteController);
|
||||||
quoteRoutes.put("/:quoteId", checkUser, getDealerMiddleware, updateQuoteController);
|
quoteRoutes.put("/:quoteId", checkUser, getDealerMiddleware, updateQuoteController);
|
||||||
|
|
||||||
|
// Reports
|
||||||
|
quoteRoutes.get("/:quoteId/report", checkUser, getDealerMiddleware, reportQuoteController);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
quoteRoutes.post("/", isAdmin, createQuoteController);
|
quoteRoutes.post("/", isAdmin, createQuoteController);
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,7 @@
|
|||||||
/* Basic Options */
|
/* Basic Options */
|
||||||
"target": "ES2022" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
|
"target": "ES2022" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
|
||||||
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
|
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
|
||||||
"lib": [
|
"lib": ["ES2022", "dom"] /* Specify library files to be included in the compilation. */,
|
||||||
"ES2022",
|
|
||||||
"dom"
|
|
||||||
] /* Specify library files to be included in the compilation. */,
|
|
||||||
|
|
||||||
"allowJs": false /* Allow javascript files to be compiled. */,
|
"allowJs": false /* Allow javascript files to be compiled. */,
|
||||||
"pretty": true,
|
"pretty": true,
|
||||||
@ -76,6 +73,15 @@
|
|||||||
"src/**/__tests__/*",
|
"src/**/__tests__/*",
|
||||||
"src/**/*.mock.*",
|
"src/**/*.mock.*",
|
||||||
"src/**/*.test.*",
|
"src/**/*.test.*",
|
||||||
"node_modules"
|
"node_modules",
|
||||||
|
|
||||||
|
"src/**/firebird/*",
|
||||||
|
|
||||||
|
"src/**/CreateDealer.useCase.ts",
|
||||||
|
"src/**/UpdateDealer.useCase.ts",
|
||||||
|
|
||||||
|
"src/**/createDealer/*",
|
||||||
|
"src/**/updateDealer/*",
|
||||||
|
"src/**/deleteDealer/*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ export interface IEntityProps {
|
|||||||
|
|
||||||
export abstract class Entity<T extends IEntityProps> {
|
export abstract class Entity<T extends IEntityProps> {
|
||||||
protected readonly _id: UniqueID;
|
protected readonly _id: UniqueID;
|
||||||
protected readonly props: T;
|
protected props: T;
|
||||||
|
|
||||||
public get id(): UniqueID {
|
public get id(): UniqueID {
|
||||||
return this._id;
|
return this._id;
|
||||||
@ -40,8 +40,6 @@ export abstract class Entity<T extends IEntityProps> {
|
|||||||
public toString(): { [s: string]: string } {
|
public toString(): { [s: string]: string } {
|
||||||
const flattenProps = this._flattenProps(this.props);
|
const flattenProps = this._flattenProps(this.props);
|
||||||
|
|
||||||
console.log(flattenProps);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: this._id.toString(),
|
id: this._id.toString(),
|
||||||
...flattenProps.map((prop: any) => String(prop)),
|
...flattenProps.map((prop: any) => String(prop)),
|
||||||
@ -51,8 +49,6 @@ export abstract class Entity<T extends IEntityProps> {
|
|||||||
public toPrimitives(): { [s: string]: any } {
|
public toPrimitives(): { [s: string]: any } {
|
||||||
const flattenProps = this._flattenProps(this.props);
|
const flattenProps = this._flattenProps(this.props);
|
||||||
|
|
||||||
console.log(flattenProps);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: this._id.value,
|
id: this._id.value,
|
||||||
...flattenProps,
|
...flattenProps,
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { Result, RuleValidator } from "../../../../../common";
|
|||||||
export interface ICreateDealer_Request_DTO {
|
export interface ICreateDealer_Request_DTO {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
lang_code: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureCreateDealer_Request_DTOIsValid(dealerDTO: ICreateDealer_Request_DTO) {
|
export function ensureCreateDealer_Request_DTOIsValid(dealerDTO: ICreateDealer_Request_DTO) {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { Result, RuleValidator } from "../../../../../common";
|
|||||||
|
|
||||||
export interface IUpdateDealer_Request_DTO {
|
export interface IUpdateDealer_Request_DTO {
|
||||||
name: string;
|
name: string;
|
||||||
language: string;
|
lang_code: string;
|
||||||
contact_information: string;
|
contact_information: string;
|
||||||
default_payment_method: string;
|
default_payment_method: string;
|
||||||
default_notes: string;
|
default_notes: string;
|
||||||
@ -14,7 +14,7 @@ export interface IUpdateDealer_Request_DTO {
|
|||||||
export function ensureUpdateDealer_Request_DTOIsValid(dealerDTO: IUpdateDealer_Request_DTO) {
|
export function ensureUpdateDealer_Request_DTOIsValid(dealerDTO: IUpdateDealer_Request_DTO) {
|
||||||
const schema = Joi.object({
|
const schema = Joi.object({
|
||||||
name: Joi.string(),
|
name: Joi.string(),
|
||||||
language: Joi.string(),
|
lang_code: Joi.string(),
|
||||||
contact_information: Joi.string(),
|
contact_information: Joi.string(),
|
||||||
default_payment_method: Joi.string(),
|
default_payment_method: Joi.string(),
|
||||||
default_notes: Joi.string(),
|
default_notes: Joi.string(),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user