This commit is contained in:
David Arranz 2024-07-12 18:13:53 +02:00
parent 8ad1c63acc
commit 533b22dd98
25 changed files with 424 additions and 115 deletions

View File

@ -10,7 +10,7 @@ import {
} from "lucide-react"; } from "lucide-react";
import { Layout, LayoutContent, LayoutHeader } from "@/components"; import { Layout, LayoutContent, LayoutHeader } from "@/components";
import { useGetIdentity } from "@/lib/hooks"; import { useGetProfile } from "@/lib/hooks";
import { import {
Badge, Badge,
Button, Button,
@ -49,7 +49,7 @@ import { useNavigate } from "react-router-dom";
export const DashboardPage = () => { export const DashboardPage = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const { data: userIdentity, status } = useGetIdentity(); const { data: userIdentity, status } = useGetProfile();
return ( return (
<Layout> <Layout>

View File

@ -202,14 +202,8 @@ export const QuoteEdit = () => {
</div> </div>
</div> </div>
<FormCurrencyField <QuoteGeneralCardEditor />
currency={quoteCurrency} <QuoteDetailsCardEditor currency={quoteCurrency} />
precision={4}
className='text-right'
label={"subtotal_price"}
disabled={form.formState.disabled}
{...form.register("subtotal_price")}
/>
<Tabs defaultValue='items' className='space-y-4'> <Tabs defaultValue='items' className='space-y-4'>
<TabsList> <TabsList>

View File

@ -1,4 +1,4 @@
import { useCustomDialog, useGetIdentity } from "@/lib/hooks"; import { useCustomDialog, useGetProfile } from "@/lib/hooks";
import { import {
Button, Button,
DropdownMenu, DropdownMenu,
@ -32,7 +32,7 @@ export const UserButton = () => {
navigate("/logout"); navigate("/logout");
}, },
}); });
const { data, status } = useGetIdentity(); const { data, status } = useGetProfile();
const openUserMenu = (event: SyntheticEvent) => { const openUserMenu = (event: SyntheticEvent) => {
event.preventDefault(); event.preventDefault();

View File

@ -24,7 +24,7 @@ export const createAxiosAuthActions = (
return { return {
success: true, success: true,
data, data,
redirectTo: "/", redirectTo: "/home",
}; };
} catch (error) { } catch (error) {
return { return {
@ -61,10 +61,18 @@ export const createAxiosAuthActions = (
); );
}, },
getIdentity: async () => { getProfile: async () => {
/**
* id: string;
* name: string;
* email: string;
* lang_code: string;
* roles: string[];
*/
try { try {
const result = await httpClient.request<IIdentity_Response_DTO>({ const result = await httpClient.request<IIdentity_Response_DTO>({
url: `${apiUrl}/auth/identity`, url: `${apiUrl}/profile`,
method: "GET", method: "GET",
}); });

View File

@ -1,4 +1,4 @@
import { IIdentity_Response_DTO } from "@shared/contexts"; import { IGetProfileResponse_DTO } from "@shared/contexts";
export type SuccessNotificationResponse = { export type SuccessNotificationResponse = {
message: string; message: string;
@ -7,7 +7,7 @@ export type SuccessNotificationResponse = {
export type PermissionResponse = unknown; export type PermissionResponse = unknown;
export type IdentityResponse = IIdentity_Response_DTO | null; export type ProfileResponse = IGetProfileResponse_DTO | null;
export type AuthActionCheckResponse = { export type AuthActionCheckResponse = {
authenticated: boolean; authenticated: boolean;
@ -39,5 +39,5 @@ export interface IAuthActions {
forgotPassword?: (params: unknown) => Promise<AuthActionResponse>; forgotPassword?: (params: unknown) => Promise<AuthActionResponse>;
updatePassword?: (params: unknown) => Promise<AuthActionResponse>; updatePassword?: (params: unknown) => Promise<AuthActionResponse>;
getPermissions?: (params?: Record<string, unknown>) => Promise<PermissionResponse>; getPermissions?: (params?: Record<string, unknown>) => Promise<PermissionResponse>;
getIdentity?: (params?: unknown) => Promise<IdentityResponse>; getProfile?: (params?: unknown) => Promise<ProfileResponse>;
} }

View File

@ -1,6 +1,6 @@
export * from "./AuthActions"; export * from "./AuthActions";
export * from "./AuthContext"; export * from "./AuthContext";
export * from "./useAuth"; export * from "./useAuth";
export * from "./useGetIdentity"; export * from "./useGetProfile";
export * from "./useIsLoggedIn"; export * from "./useIsLoggedIn";
export * from "./useLogin"; export * from "./useLogin";

View File

@ -1,16 +0,0 @@
import { IdentityResponse, useAuth } from "@/lib/hooks";
import { UseQueryOptions, useQuery } from "@tanstack/react-query";
import { useQueryKey } from "../useQueryKey";
export const useGetIdentity = (queryOptions?: UseQueryOptions<IdentityResponse>) => {
const keys = useQueryKey();
const { getIdentity } = useAuth();
const result = useQuery<IdentityResponse>({
queryKey: keys().auth().action("identity").get(),
queryFn: getIdentity,
...queryOptions,
});
return result;
};

View File

@ -0,0 +1,16 @@
import { ProfileResponse, useAuth } from "@/lib/hooks";
import { UseQueryOptions, useQuery } from "@tanstack/react-query";
import { useQueryKey } from "../useQueryKey";
export const useGetProfile = (queryOptions?: UseQueryOptions<ProfileResponse>) => {
const keys = useQueryKey();
const { getProfile } = useAuth();
const result = useQuery<ProfileResponse>({
queryKey: keys().auth().action("profile").get(),
queryFn: getProfile,
...queryOptions,
});
return result;
};

View File

@ -17,7 +17,7 @@ export const useLogin = (params?: UseMutationOptions<AuthActionResponse, Error,
onSuccess: (data, variables, context) => { onSuccess: (data, variables, context) => {
const { success, redirectTo } = data; const { success, redirectTo } = data;
if (success && redirectTo) { if (success && redirectTo) {
navigate(redirectTo || "/", { replace: true }); navigate(redirectTo || "/home", { replace: false });
} }
if (onSuccess) { if (onSuccess) {
onSuccess(data, variables, context); onSuccess(data, variables, context);

View File

@ -1,7 +1,7 @@
import { useGetIdentity } from "../useAuth"; import { useGetProfile } from "../useAuth";
export const usePreferredLanguage = () => { export const usePreferredLanguage = () => {
const { data } = useGetIdentity(); const { data } = useGetProfile();
if (!data || !data.language) { if (!data || !data.language) {
return navigator.languages && navigator.languages.length return navigator.languages && navigator.languages.length

View File

@ -16,7 +16,7 @@ type DataMutationActions =
type AuthActionType = type AuthActionType =
| "login" | "login"
| "logout" | "logout"
| "identity" | "profile"
| "register" | "register"
| "forgotPassword" | "forgotPassword"
| "check" | "check"

View File

@ -4,36 +4,243 @@
"cancel": "Cancel", "cancel": "Cancel",
"no": "No", "no": "No",
"yes": "Yes", "yes": "Yes",
"Accept": "Accept" "save": "Save",
"accept": "OK",
"hide": "Ocultar",
"back": "Back",
"upload": "Upload",
"continue": "Continue",
"sort_asc": "Asc",
"sort_asc_description": "En order ascendente. Click para ordenar descendentemente.",
"sort_desc": "Desc",
"sort_desc_description": "En orden descendente. Click para ordenar ascendentemente.",
"sort_none_description": "Sin orden. Click para ordenar ascendentemente.",
"rows_selected": "{{count}} de {{total}} fila(s) seleccionadas.",
"rows_per_page": "Filas por página",
"num_page_of_total": "Página {{count}} de {{total}}",
"go_to_first_page": "Ir a la primera página",
"go_to_prev_page": "Ir a la página anterior",
"go_to_next_page": "Ir a la página siguiente",
"go_to_last_page": "Ir a la última página",
"filter_placeholder": "Escribe aquí para filtrar...",
"reset_filter": "Quitar el filtro",
"error": "Error",
"actions": "Acciones",
"open_menu": "Abrir el menú",
"duplicate_rows": "Duplicar",
"duplicate_rows_tooltip": "Duplica las fila(s) seleccionadas(s)",
"pick_date": "Elige una fecha",
"required_field": "Este campo es obligatorio",
"unsaved_changes_prompt": "Los últimos cambios no se han guardado. Si continúas, se perderán",
"edit": "Editar"
}, },
"main_menu": { "main_menu": {
"home": "Home", "home": "Inicio",
"settings": "Settings", "settings": "Ajustes",
"dealers": "Dealers", "dealers": "Distribuidores",
"catalog": "Catalog", "catalog": "Catálogo",
"quotes": "Quotes", "quotes": "Cotizaciones",
"search_placeholder": "Search product, quotes, etc...", "search_placeholder": "Buscar productos, cotizaciones, etc...",
"user": { "user": {
"user_menu": "User menu", "user_menu": "Menú del usuario",
"my_account": "My account", "my_account": "Mi cuenta",
"profile": "Profile", "profile": "Perfil",
"settings": "Settings", "settings": "Ajustes",
"support": "Support", "support": "Soporte",
"logout": "Logout" "logout": "Salir"
}, },
"logout": {} "logout": {}
}, },
"login_page": { "login_page": {
"title": "Uecko Quotes", "title": "Presupuestador para distribuidores",
"description": "Enter your email address and password to login", "description": "Introduzca su dirección de correo electrónico y contraseña para acceder",
"email_label": "Email", "email_label": "Email",
"email_placeholder": "user@sample.com", "email_placeholder": "micorreo@ejemplo.com",
"password_label": "Password", "password_label": "Contraseña",
"forgotten_password": "Forgot your password?", "forgotten_password": "¿Has olvidado tu contraseña?",
"become_dealer": "Do you want to become a Uecko dealer?", "become_dealer": "¿Quieres ser distribuidor de Uecko?",
"contact_us": "Contact us", "contact_us": "Contacta con nosotros",
"login": "Login", "login": "Entrar"
"error": "Error" },
"dashboard": {
"welcome": "Bienvenido"
},
"catalog": {
"list": {
"title": "Catálogo de artículos",
"columns": {
"description": "Descripción",
"points": "Puntos",
"retail_price": "PVP"
}
}
},
"quotes": {
"list": {
"title": "Quotes",
"subtitle": "",
"tabs": {
"all": "All",
"draft": "Draft",
"archived": "Archive"
},
"columns": {
"date": "Date",
"reference": "Reference",
"status": "Status",
"customer_information": "Customer",
"total_price": "Imp. total"
}
},
"create": {
"title": "New quote",
"buttons": {
"save_quote": "Guardar cotización",
"discard": "Descartar"
},
"tabs": {
"general": "Datos generales",
"items": "Contenido",
"documents": "Documentos",
"history": "Historial"
},
"form_groups": {
"general": {
"title": "Datos generales",
"desc": "Datos generales y cliente al que va la cotización"
},
"status": {
"title": "Estado",
"desc": "Estado de la cotización"
},
"items": {
"title": "Contenido de la cotización",
"desc": "Líneas de detalle de la cotización. Ayúdese del catálogo para rellenar más fácilmente el contenido."
},
"documents": {
"title": "Documentos",
"desc": "Añada adjuntar con su cotización documentos como fotos, planos, croquis, etc."
},
"history": {
"title": "",
"desc": ""
}
},
"edit": {
"title": "Cotización"
}
},
"edit": {
"title": "Cotización"
},
"status": {
"draft": "Borrador"
},
"form_fields": {
"date": {
"label": "Fecha",
"desc": "Fecha de esta cotización",
"placeholder": ""
},
"reference": {
"label": "Referencia",
"desc": "Referencia para esta cotización",
"placeholder": ""
},
"lang_code": {
"label": "Idioma",
"desc": "Idioma de la cotización",
"placeholder": ""
},
"currency_code": {
"label": "Moneda",
"desc": "Moneda de la cotización",
"placeholder": ""
},
"customer_information": {
"label": "Datos del cliente",
"desc": "Escriba el nombre del cliente en la primera línea, la direccion en la segunda y el código postal y ciudad en la tercera.",
"placeholder": "Nombre y apellidos\nCalle y número\nCódigo postal y ciudad..."
},
"payment_method": {
"label": "Forma de pago",
"placeholder": "placeholder",
"desc": "desc"
},
"notes": {
"label": "Notas",
"placeholder": "",
"desc": "desc"
},
"validity": {
"label": "Validez de la cotización",
"placeholder": "",
"desc": "desc"
},
"items": {
"quantity": {
"label": "Cantidad",
"placeholder": "",
"desc": ""
},
"description": {
"label": "Descripción",
"placeholder": "",
"desc": ""
},
"unit_price": {
"label": "Imp. unitario",
"placeholder": "",
"desc": "Importe unitario del artículo"
},
"subtotal_price": {
"label": "Subtotal",
"placeholder": "",
"desc": ""
},
"discount": {
"label": "Dto (%)",
"placeholder": "",
"desc": "Porcentaje de descuento"
},
"total_price": {
"label": "Imp. total",
"placeholder": "",
"desc": "Importe total con el descuento ya aplicado"
}
}
}
},
"settings": {
"title": "Ajustes",
"quotes": {
"title": "Cotizaciones",
"contact_information": {
"label": "Información de contacto",
"placeholder": "placeholder",
"desc": "Información de contacto"
},
"default_payment_method": {
"label": "Forma de pago",
"placeholder": "placeholder",
"desc": "desc"
},
"default_notes": {
"label": "Notas",
"placeholder": "",
"desc": "desc"
},
"default_legal_terms": {
"label": "Cláusulas legales",
"placeholder": "",
"desc": "desc"
},
"default_quote_validity": {
"label": "Validez por defecto",
"placeholder": "",
"desc": ""
}
}
} }
} }
} }

View File

@ -27,6 +27,7 @@ export interface IAuthUser {
isUser: boolean; isUser: boolean;
isAdmin: boolean; isAdmin: boolean;
getRoles: () => AuthUserRole[]; getRoles: () => AuthUserRole[];
getRolesArray: () => string[];
verifyPassword: (candidatePassword: string) => boolean; verifyPassword: (candidatePassword: string) => boolean;
} }
@ -77,6 +78,10 @@ export class AuthUser extends AggregateRoot<IAuthUserProps> implements IAuthUser
return this.roles; return this.roles;
} }
public getRolesArray(): string[] {
return this.getRoles()?.map((rol) => rol.toString());
}
public verifyPassword(candidatePassword: string): boolean { public verifyPassword(candidatePassword: string): boolean {
return this.props.password.verifyPassword(candidatePassword); return this.props.password.verifyPassword(candidatePassword);
} }

View File

@ -15,8 +15,8 @@ export const identityPresenter: IIdentityPresenter = {
id: user.id.toString(), id: user.id.toString(),
name: user.name.toString(), name: user.name.toString(),
email: user.email.toString(), email: user.email.toString(),
language: user.language.toString(), lang_code: user.language.toString(),
roles: user.getRoles()?.map((rol) => rol.toString()), roles: user.getRolesArray(),
}; };
}, },
}; };

View File

@ -1,20 +1,40 @@
import { AggregateRoot, IDomainError, Result, UniqueID } from "@shared/contexts"; import { DealerStatus } from "@/contexts/sales/domain";
import {
AggregateRoot,
CurrencyData,
IDomainError,
Language,
Name,
Note,
Result,
UniqueID,
} from "@shared/contexts";
export interface IProfileProps { export interface IProfileProps {
contactInformation: string; name: Name;
defaultPaymentMethod: string; language: Language;
defaultNotes: string; status: DealerStatus;
defaultLegalTerms: string; currency: CurrencyData;
defaultQuoteValidity: string;
contactInformation: Note;
defaultPaymentMethod: Note;
defaultNotes: Note;
defaultLegalTerms: Note;
defaultQuoteValidity: Note;
} }
export interface IProfile { export interface IProfile {
id: UniqueID; id: UniqueID;
contactInformation: string; name: Name;
defaultPaymentMethod: string; language: Language;
defaultNotes: string; status: DealerStatus;
defaultLegalTerms: string; currency: CurrencyData;
defaultQuoteValidity: string;
contactInformation: Note;
defaultPaymentMethod: Note;
defaultNotes: Note;
defaultLegalTerms: Note;
defaultQuoteValidity: Note;
} }
export class Profile extends AggregateRoot<IProfileProps> implements IProfile { export class Profile extends AggregateRoot<IProfileProps> implements IProfile {
@ -23,23 +43,39 @@ export class Profile extends AggregateRoot<IProfileProps> implements IProfile {
return Result.ok<Profile>(profile); return Result.ok<Profile>(profile);
} }
get contactInformation(): string { get name(): Name {
return this.props.name;
}
get language(): Language {
return this.props.language;
}
get status(): DealerStatus {
return this.props.status;
}
get currency(): CurrencyData {
return this.props.currency;
}
get contactInformation(): Note {
return this.props.contactInformation; return this.props.contactInformation;
} }
get defaultPaymentMethod(): string { get defaultPaymentMethod(): Note {
return this.props.defaultPaymentMethod; return this.props.defaultPaymentMethod;
} }
get defaultNotes(): string { get defaultNotes(): Note {
return this.props.defaultNotes; return this.props.defaultNotes;
} }
get defaultLegalTerms(): string { get defaultLegalTerms(): Note {
return this.props.defaultLegalTerms; return this.props.defaultLegalTerms;
} }
get defaultQuoteValidity(): string { get defaultQuoteValidity(): Note {
return this.props.defaultQuoteValidity; return this.props.defaultQuoteValidity;
} }
} }

View File

@ -41,7 +41,7 @@ export class ProfileRepository extends SequelizeRepository<Profile> implements I
} }
public async getByUserId(userId: UniqueID): Promise<Profile | null> { public async getByUserId(userId: UniqueID): Promise<Profile | null> {
const rawDealer: any = await this._getBy("Profile_Model", "user_id", userId.toPrimitive()); const rawDealer: any = await this._getBy("Dealer_Model", "user_id", userId.toPrimitive());
if (!rawDealer === true) { if (!rawDealer === true) {
return null; return null;

View File

@ -1,8 +1,8 @@
import { IUseCaseError, UseCaseError } from "@/contexts/common/application/useCases"; import { IUseCaseError, UseCaseError } from "@/contexts/common/application/useCases";
import { ExpressController } from "@/contexts/common/infrastructure/express"; import { ExpressController } from "@/contexts/common/infrastructure/express";
import { User } from "@/contexts/users/domain/entities/User";
import { IGetProfileResponse_DTO } from "@shared/contexts"; import { IGetProfileResponse_DTO } from "@shared/contexts";
import { AuthUser } from "@/contexts/auth/domain";
import { IServerError } from "@/contexts/common/domain/errors"; import { IServerError } from "@/contexts/common/domain/errors";
import { IInfrastructureError, InfrastructureError } from "@/contexts/common/infrastructure"; import { IInfrastructureError, InfrastructureError } from "@/contexts/common/infrastructure";
import { GetProfileUseCase } from "@/contexts/profile/application/GetProfile.useCase"; import { GetProfileUseCase } from "@/contexts/profile/application/GetProfile.useCase";
@ -30,7 +30,7 @@ export class GetProfileController extends ExpressController {
} }
async executeImpl(): Promise<any> { async executeImpl(): Promise<any> {
const user = <User | undefined>this.req.user; const user = <AuthUser>this.req.user;
if (!user) { if (!user) {
const errorMessage = "Unexpected missing user data"; const errorMessage = "Unexpected missing user data";
@ -42,17 +42,17 @@ export class GetProfileController extends ExpressController {
} }
try { try {
const result = await this.useCase.execute({ const profileOrError = await this.useCase.execute({
userId: user.id, userId: user.id,
}); });
if (result.isFailure) { if (profileOrError.isFailure) {
return this._handleExecuteError(result.error); return this._handleExecuteError(profileOrError.error);
} }
const profile = result.object; const profile = profileOrError.object;
return this.ok<IGetProfileResponse_DTO>(this.presenter.map(profile, this.context)); return this.ok<IGetProfileResponse_DTO>(this.presenter.map(profile, user, this.context));
} catch (e: unknown) { } catch (e: unknown) {
return this.fail(e as IServerError); return this.fail(e as IServerError);
} }

View File

@ -1,20 +1,32 @@
import { AuthUser } from "@/contexts/auth/domain";
import { Profile } from "@/contexts/profile/domain"; import { Profile } from "@/contexts/profile/domain";
import { IProfileContext } from "@/contexts/profile/infrastructure/Profile.context"; import { IProfileContext } from "@/contexts/profile/infrastructure/Profile.context";
import { IGetProfileResponse_DTO } from "@shared/contexts"; import { IGetProfileResponse_DTO } from "@shared/contexts";
export interface IGetProfilePresenter { export interface IGetProfilePresenter {
map: (profile: Profile, context: IProfileContext) => IGetProfileResponse_DTO; map: (profile: Profile, user: AuthUser, context: IProfileContext) => IGetProfileResponse_DTO;
} }
export const GetProfilePresenter: IGetProfilePresenter = { export const GetProfilePresenter: IGetProfilePresenter = {
map: (profile: Profile, context: IProfileContext): IGetProfileResponse_DTO => { map: (profile: Profile, user: AuthUser, context: IProfileContext): IGetProfileResponse_DTO => {
return { return {
dealer_id: profile.id.toString(), name: user.name.toString(),
contact_information: profile.contactInformation, email: user.email.toString(),
default_payment_method: profile.defaultPaymentMethod, lang_code: user.language.code,
default_notes: profile.defaultNotes, roles: user.getRolesArray(),
default_legal_terms: profile.defaultLegalTerms, dealer: {
default_quote_validity: profile.defaultQuoteValidity, id: profile.id.toString(),
name: profile.name.toString(),
status: profile.status.toString(),
lang_code: profile.language.toString(),
currency_code: profile.currency.toString(),
contact_information: profile.contactInformation.toString(),
default_payment_method: profile.defaultPaymentMethod.toString(),
default_notes: profile.defaultNotes.toString(),
default_legal_terms: profile.defaultLegalTerms.toString(),
default_quote_validity: profile.defaultQuoteValidity.toString(),
},
}; };
}, },
}; };

View File

@ -3,7 +3,9 @@ import {
MapperParamsType, MapperParamsType,
SequelizeMapper, SequelizeMapper,
} from "@/contexts/common/infrastructure"; } from "@/contexts/common/infrastructure";
import { UniqueID } from "@shared/contexts"; import { DealerStatus } from "@/contexts/sales/domain";
import { Dealer_Model } from "@/contexts/sales/infrastructure/sequelize";
import { CurrencyData, Language, Name, Note, UniqueID } from "@shared/contexts";
import { IProfileProps, Profile } from "../../domain"; import { IProfileProps, Profile } from "../../domain";
import { IProfileContext } from "../Profile.context"; import { IProfileContext } from "../Profile.context";
import { ProfileCreationAttributes, Profile_Model } from "../sequelize"; import { ProfileCreationAttributes, Profile_Model } from "../sequelize";
@ -19,13 +21,29 @@ class ProfileMapper
super(props); super(props);
} }
protected toDomainMappingImpl(source: Profile_Model, params: any): Profile { protected toDomainMappingImpl(source: Dealer_Model, params: any): Profile {
const name = this.mapsValue(source, "name", Name.create);
const status = this.mapsValue(source, "status", DealerStatus.create);
const language = this.mapsValue(source, "lang_code", Language.createFromCode);
const currency = this.mapsValue(source, "currency_code", CurrencyData.createFromCode);
const contactInformation = this.mapsValue(source, "contact_information", Note.create);
const defaultPaymentMethod = this.mapsValue(source, "default_payment_method", Note.create);
const defaultNotes = this.mapsValue(source, "default_notes", Note.create);
const defaultLegalTerms = this.mapsValue(source, "default_legal_terms", Note.create);
const defaultQuoteValidity = this.mapsValue(source, "default_quote_validity", Note.create);
const props: IProfileProps = { const props: IProfileProps = {
contactInformation: source.contact_information, name,
defaultPaymentMethod: source.default_payment_method, status,
defaultNotes: source.default_notes, language,
defaultLegalTerms: source.default_legal_terms, currency,
defaultQuoteValidity: source.default_quote_validity,
contactInformation,
defaultPaymentMethod,
defaultNotes,
defaultLegalTerms,
defaultQuoteValidity,
}; };
const id = this.mapsValue(source, "id", UniqueID.create); const id = this.mapsValue(source, "id", UniqueID.create);

View File

@ -1,5 +1,6 @@
import { import {
AggregateRoot, AggregateRoot,
CurrencyData,
IDomainError, IDomainError,
KeyValueMap, KeyValueMap,
Language, Language,
@ -12,10 +13,11 @@ import { DealerStatus } from "./DealerStatus";
export interface IDealerProps { export interface IDealerProps {
user_id: UniqueID; user_id: UniqueID;
name: Name; name: Name;
logo: string; //logo: string;
language: Language; language: Language;
additionalInfo: KeyValueMap; additionalInfo: KeyValueMap;
status: DealerStatus; status: DealerStatus;
currency: CurrencyData;
} }
export interface IDealer { export interface IDealer {
@ -26,6 +28,7 @@ export interface IDealer {
additionalInfo: KeyValueMap; additionalInfo: KeyValueMap;
status: DealerStatus; status: DealerStatus;
currency: CurrencyData;
} }
export class Dealer extends AggregateRoot<IDealerProps> implements IDealer { export class Dealer extends AggregateRoot<IDealerProps> implements IDealer {
@ -53,4 +56,8 @@ export class Dealer extends AggregateRoot<IDealerProps> implements IDealer {
get additionalInfo(): KeyValueMap { get additionalInfo(): KeyValueMap {
return this.props.additionalInfo; return this.props.additionalInfo;
} }
get currency(): CurrencyData {
return this.props.currency;
}
} }

View File

@ -3,7 +3,7 @@ import {
MapperParamsType, MapperParamsType,
SequelizeMapper, SequelizeMapper,
} from "@/contexts/common/infrastructure"; } from "@/contexts/common/infrastructure";
import { KeyValueMap, Language, Name, UniqueID } from "@shared/contexts"; import { CurrencyData, KeyValueMap, Language, Name, UniqueID } from "@shared/contexts";
import { Dealer, DealerStatus, IDealerProps } from "../../domain/entities"; import { Dealer, DealerStatus, IDealerProps } from "../../domain/entities";
import { ISalesContext } from "../Sales.context"; import { ISalesContext } from "../Sales.context";
import { DealerCreationAttributes, Dealer_Model } from "../sequelize"; import { DealerCreationAttributes, Dealer_Model } from "../sequelize";
@ -24,6 +24,7 @@ class DealerMapper
const user_id = this.mapsValue(source, "user_id", UniqueID.create); const user_id = this.mapsValue(source, "user_id", UniqueID.create);
const status = this.mapsValue(source, "status", DealerStatus.create); const status = this.mapsValue(source, "status", DealerStatus.create);
const language = this.mapsValue(source, "lang_code", Language.createFromCode); const language = this.mapsValue(source, "lang_code", Language.createFromCode);
const currency = this.mapsValue(source, "currency_code", CurrencyData.createFromCode);
const additionalInfoOrError = KeyValueMap.create([ const additionalInfoOrError = KeyValueMap.create([
["contact_information", source.contact_information], ["contact_information", source.contact_information],
@ -35,10 +36,11 @@ class DealerMapper
const props: IDealerProps = { const props: IDealerProps = {
user_id, user_id,
logo: "", //logo: "",
name, name,
status, status,
language, language,
currency,
additionalInfo: additionalInfoOrError.object, additionalInfo: additionalInfoOrError.object,
}; };
@ -57,7 +59,8 @@ class DealerMapper
id: source.id.toPrimitive(), id: source.id.toPrimitive(),
user_id: source.user_id.toPrimitive(), user_id: source.user_id.toPrimitive(),
//contact_id: undefined, //contact_id: undefined,
logo: "", currency_code: source.currency.toPrimitive(),
//logo: "",
name: source.name.toPrimitive(), name: source.name.toPrimitive(),
status: source.status.toPrimitive(), status: source.status.toPrimitive(),
lang_code: source.language.toPrimitive(), lang_code: source.language.toPrimitive(),

View File

@ -55,6 +55,7 @@ export class Dealer_Model extends Model<
declare default_quote_validity: CreationOptional<string>; declare default_quote_validity: CreationOptional<string>;
declare status: CreationOptional<string>; declare status: CreationOptional<string>;
declare lang_code: CreationOptional<string>; declare lang_code: CreationOptional<string>;
declare currency_code: CreationOptional<string>;
declare user: NonAttribute<User_Model>; declare user: NonAttribute<User_Model>;
declare quotes: NonAttribute<Quote_Model>; declare quotes: NonAttribute<Quote_Model>;
@ -90,6 +91,12 @@ export default (sequelize: Sequelize) => {
defaultValue: "es", defaultValue: "es",
}, },
currency_code: {
type: new DataTypes.STRING(3),
allowNull: false,
defaultValue: "EUR",
},
status: { status: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,

View File

@ -1,5 +1,4 @@
import { checkUser, createLoginController } from "@/contexts/auth"; import { checkUser, createLoginController } from "@/contexts/auth";
import { createIdentityController } from "@/contexts/auth/infrastructure/express/controllers/identity";
import Express from "express"; import Express from "express";
import passport from "passport"; import passport from "passport";
@ -27,12 +26,15 @@ export const authRouter = (appRouter: Express.Router) => {
authRoutes.post("/register"); authRoutes.post("/register");
/*
-> Sustituido por /profile
authRoutes.get( authRoutes.get(
"/identity", "/identity",
checkUser, checkUser,
(req: Express.Request, res: Express.Response, next: Express.NextFunction) => (req: Express.Request, res: Express.Response, next: Express.NextFunction) =>
createIdentityController(res.locals["context"]).execute(req, res, next) createIdentityController(res.locals["context"]).execute(req, res, next)
); );*/
appRouter.use("/auth", authRoutes); appRouter.use("/auth", authRoutes);
}; };

View File

@ -2,6 +2,6 @@ export interface IIdentity_Response_DTO {
id: string; id: string;
name: string; name: string;
email: string; email: string;
language: string; lang_code: string;
roles: string[]; roles: string[];
} }

View File

@ -1,8 +1,18 @@
export interface IGetProfileResponse_DTO { export interface IGetProfileResponse_DTO {
dealer_id: string; name: string;
contact_information: string; email: string;
default_payment_method: string; lang_code: string;
default_notes: string; roles: string[];
default_legal_terms: string; dealer: {
default_quote_validity: string; id: string;
name: string;
contact_information: string;
default_payment_method: string;
default_notes: string;
default_legal_terms: string;
default_quote_validity: string;
status: string;
lang_code: string;
currency_code: string;
};
} }