Enhance Salesforce Account and Contact Creation in Signup Workflow

- Updated SalesforceAccountService to map gender values to Salesforce picklist values and added date of birth handling for contact creation.
- Modified SignupWorkflowService to require gender and date of birth during account creation, ensuring complete data submission.
- Adjusted SignupAccountResolverService to include gender and date of birth in account creation logic, improving data integrity.
- Introduced SalesforceContactRecord interface in domain to standardize contact data structure, enhancing type safety and validation.
This commit is contained in:
barsa 2026-01-06 16:52:02 +09:00
parent 1a3032bbd3
commit a8580b0d61
5 changed files with 66 additions and 31 deletions

View File

@ -177,7 +177,7 @@ export class SalesforceAccountService {
const accountPayload: Record<string, unknown> = {
Name: `${data.firstName} ${data.lastName}`,
Phone: data.phone,
// Phone is stored on Contact, not Account
// Portal tracking fields
[this.portalStatusField]: "Active",
[this.portalSourceField]: "Portal Checkout",
@ -236,12 +236,24 @@ export class SalesforceAccountService {
email: data.email,
});
// Map gender values to Salesforce picklist values
const mapGenderToSalesforce = (gender: "male" | "female" | "other"): string => {
const mapping: Record<"male" | "female" | "other", string> = {
male: "男性",
female: "女性",
other: "Other",
};
return mapping[gender];
};
const contactPayload: Record<string, unknown> = {
AccountId: data.accountId,
FirstName: data.firstName,
LastName: data.lastName,
Email: data.email,
Phone: data.phone,
MobilePhone: data.phone,
Sex__c: mapGenderToSalesforce(data.gender),
Birthdate: data.dateOfBirth, // Salesforce expects YYYY-MM-DD format
};
try {
@ -350,4 +362,6 @@ export interface CreateSalesforceContactRequest {
lastName: string;
email: string;
phone: string;
gender: "male" | "female" | "other";
dateOfBirth: string; // YYYY-MM-DD format
}

View File

@ -35,7 +35,7 @@ import {
*
* Orchestrates the signup process by coordinating:
* - SignupValidationService: Validates customer numbers and preflight checks
* - SignupAccountResolverService: Resolves Salesforce accounts
* - SalesforceAccountService: Creates new Salesforce accounts and contacts
* - SignupWhmcsService: Creates WHMCS clients
* - SignupUserCreationService: Creates portal users with ID mappings
*/
@ -210,38 +210,16 @@ export class SignupWorkflowService {
}
/**
* Resolve Salesforce account for signup
* Either finds existing account by customer number or creates new one
* Create a new Salesforce account for signup
* Always creates a new account - no lookup by customer number
*/
private async resolveSalesforceAccount(signupData: SignupRequest): Promise<{
accountSnapshot: SignupAccountSnapshot;
customerNumberForWhmcs: string | null;
}> {
const { email, firstName, lastName, phone, address, sfNumber } = signupData;
const normalizedCustomerNumber = this.accountResolver.normalizeCustomerNumber(sfNumber);
const { email, firstName, lastName, phone, address, gender, dateOfBirth } = signupData;
if (normalizedCustomerNumber) {
// Existing customer - find account by customer number
const resolved = await this.accountResolver.getAccountSnapshot(normalizedCustomerNumber);
if (!resolved) {
throw new BadRequestException(
`Salesforce account not found for Customer Number: ${normalizedCustomerNumber}`
);
}
if (resolved.WH_Account__c && resolved.WH_Account__c.trim() !== "") {
throw new ConflictException(
"You already have an account. Please use the login page to access your existing account."
);
}
return {
accountSnapshot: resolved,
customerNumberForWhmcs: normalizedCustomerNumber,
};
}
// New customer - create Salesforce account
// Check if account already exists by email
const normalizedEmail = email.toLowerCase().trim();
const existingAccount = await this.salesforceAccountService.findByEmail(normalizedEmail);
if (existingAccount) {
@ -266,6 +244,15 @@ export class SignupWorkflowService {
throw new BadRequestException("Phone number is required for account creation");
}
if (!gender) {
throw new BadRequestException("Gender is required for account creation");
}
if (!dateOfBirth) {
throw new BadRequestException("Date of birth is required for account creation");
}
// Create new Salesforce account
const created = await this.salesforceAccountService.createAccount({
firstName,
lastName,
@ -280,6 +267,8 @@ export class SignupWorkflowService {
lastName,
email: normalizedEmail,
phone,
gender,
dateOfBirth,
// Address not added to Salesforce during signup
});

View File

@ -28,7 +28,8 @@ export class SignupAccountResolverService {
async resolveOrCreate(
signupData: SignupRequest
): Promise<{ snapshot: SignupAccountSnapshot; customerNumber: string | null }> {
const { sfNumber, email, firstName, lastName, phone, address } = signupData;
const { sfNumber, email, firstName, lastName, phone, address, gender, dateOfBirth } =
signupData;
const normalizedCustomerNumber = this.normalizeCustomerNumber(sfNumber);
if (normalizedCustomerNumber) {
@ -73,6 +74,14 @@ export class SignupAccountResolverService {
throw new BadRequestException("Phone number is required for account creation");
}
if (!gender) {
throw new BadRequestException("Gender is required for account creation");
}
if (!dateOfBirth) {
throw new BadRequestException("Date of birth is required for account creation");
}
const created = await this.salesforceAccountService.createAccount({
firstName,
lastName,
@ -86,6 +95,8 @@ export class SignupAccountResolverService {
lastName,
email: normalizedEmail,
phone,
gender,
dateOfBirth,
});
const snapshot: SignupAccountSnapshot = {

View File

@ -42,6 +42,23 @@ export interface SalesforceAccountRecord {
[key: string]: unknown;
}
/**
* Salesforce contact record structure
* Raw structure from Salesforce API
*/
export interface SalesforceContactRecord {
Id: string;
AccountId?: string | null;
FirstName?: string | null;
LastName?: string | null;
Email?: string | null;
MobilePhone?: string | null;
Phone?: string | null;
Sex__c?: string | null;
Birthdate?: string | null; // YYYY-MM-DD format
[key: string]: unknown;
}
// ============================================================================
// Re-export Types from Schema (Schema-First Approach)
// ============================================================================

View File

@ -10,7 +10,11 @@ export * from "./portal/index.js";
export * from "./whmcs/index.js";
// Provider-specific integration types (BFF-only convenience re-exports)
export type { SalesforceAccountFieldMap, SalesforceAccountRecord } from "../contract.js";
export type {
SalesforceAccountFieldMap,
SalesforceAccountRecord,
SalesforceContactRecord,
} from "../contract.js";
export type {
WhmcsAddClientParams,
WhmcsValidateLoginParams,