코드리뷰 전
type AuthSuccessResponse = {
data: {
token: string;
validDate: string;
};
result: '00';
message: string;
};
type AuthFailureResponse = {
result: '99';
message: string;
};
type AuthResponse = AuthSuccessResponse | AuthFailureResponse;
type ApiPayload = {
[key: string]: any;
};
type RequestType = 'text/xml' | 'application/json' | 'x-www-form-urlencoded';
class CosmaxService {
private authToken: string | null = '0ti6MDBcompanyx9jVB6LmJeusg==';
private readonly BASE_URL: string = '<https://cosmaxapi.mobydicksoft.com>';
private async validateToken(): Promise<void> {
const params = new URLSearchParams();
params.append('token', this.authToken || '');
params.append('dm_id', '5');
const response = await fetch(`${this.BASE_URL}/auth/auth_key.jsp`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params,
});
const data: AuthResponse = await response.json();
if (data.result === '99') {
console.log('기존 토큰이 유효하지 않음. 새로운 토큰 발급 중...');
await this.createAuthKey();
return;
}
this.authToken = data.data.token;
}
private async createAuthKey(): Promise<void> {
const params = new URLSearchParams();
params.append('dm_id', '5');
params.append('key', this.authToken);
const response = await fetch(`${this.BASE_URL}/auth/create_auth_key.jsp`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params,
});
const data: AuthResponse = await response.json();
if (data.result === '99') {
throw new Error(data.message);
}
this.authToken = data.data.token;
}
// 유효한 토큰 확인 함수
private async ensureValidToken(): Promise<void> {
await this.validateToken();
}
// API 요청 처리 함수
public async makeApiRequest<T>(
endpoint: string,
payload: ApiPayload,
requestType: RequestType = 'application/json',
): Promise<T> {
await this.ensureValidToken();
let body: string;
const headers: HeadersInit = {};
// 각 요청에서 token을 파라미터로 추가
payload.token = this.authToken;
// 요청 타입에 따라 처리
if (requestType === 'x-www-form-urlencoded') {
headers['Content-Type'] = 'application/x-www-form-urlencoded';
const params = new URLSearchParams();
Object.keys(payload).forEach((key) => params.append(key, payload[key]));
body = params.toString();
} else if (requestType === 'application/json') {
headers['Content-Type'] = 'application/json';
body = JSON.stringify(payload);
} else if (requestType === 'text/xml') {
headers['Content-Type'] = 'text/xml';
body = payload as string; // XML 요청은 미리 문자열로 준비되어 있어야 함
} else {
throw new Error('Unsupported request type');
}
const response = await fetch(`${this.BASE_URL}${endpoint}`, {
method: 'POST',
headers,
body,
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Error ${response.status}: ${errorText}`);
}
const data: T = await response.json();
return data;
}
}
const cosmaxService = new CosmaxService();
export default cosmaxService;
// 사용예시
type ApiPayload = {
token: string;
dm_id: number;
ord_id: string;
ord_data: Array<{ prd_num: number; amt: number; sale_price: number; m_time: string }>;
};
async function modifyOrder() {
const payload: ApiPayload = {
token: 'token',
dm_id: 5,
ord_id: 'ord_id', // 주문번호
ord_data: [
{ prd_num: 1, amt: 1, sale_price: 5000, m_time: '1000' },
{ prd_num: 2, amt: 2, sale_price: 5000, m_time: '0101' },
{ prd_num: 3, amt: 1, sale_price: 5000, m_time: '0001' },
],
};
try {
const response = await cosmaxService.makeApiRequest<{ ord_id: string; result: string; message: string }>(
'/company/order_prd_modify.jsp',
payload,
'application/json', // Request type을 'application/json'으로 설정
);
console.log('수정된 주문 결과:', response);
} catch (error) {
console.error('주문 정보 수정 실패:', error);
}
}
type AuthSuccessResponse = {
data: {
token: string;
validDate: string;
};
result: '00';
message: string;
};
type AuthFailureResponse = {
result: '99';
message: string;
};
type AuthResponse = AuthSuccessResponse | AuthFailureResponse;
type ApiPayload = {
[key: string]: any;
};
type RequestType = 'text/xml' | 'application/json' | 'x-www-form-urlencoded';
class CosmaxService {
private authToken: string | null = '0ti6MDBcompanyx9jVB6LmJeusg==';
private readonly BASE_URL: string = '<https://cosmaxapi.mobydicksoft.com>';
// 계정 관련 정보들을 변수화
private mem_id: string;
private dm_id: number;
private str_id: number;
constructor(mem_id: string, dm_id: number, str_id: number) {
this.mem_id = mem_id;
this.dm_id = dm_id;
this.str_id = str_id;
}
private async validateToken(): Promise<void> {
const params = new URLSearchParams();
params.append('token', this.authToken || '');
params.append('dm_id', '5');
const response = await fetch(`${this.BASE_URL}/auth/auth_key.jsp`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params,
});
const data: AuthResponse = await response.json();
if (data.result === '99') {
console.log('기존 토큰이 유효하지 않음. 새로운 토큰 발급 중...');
await this.createAuthKey();
return;
}
this.authToken = data.data.token;
}
private async createAuthKey(): Promise<void> {
const params = new URLSearchParams();
params.append('dm_id', this.dm_id.toString());
params.append('key', this.authToken);
const response = await fetch(`${this.BASE_URL}/auth/create_auth_key.jsp`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params,
});
const data: AuthResponse = await response.json();
if (data.result === '99') {
throw new Error(data.message);
}
this.authToken = data.data.token;
}
private async ensureValidToken(): Promise<void> {
await this.validateToken();
}
// API 요청 처리 함수
private async makeApiRequest<T>(
endpoint: string,
payload: ApiPayload,
requestType: RequestType = 'application/json',
): Promise<T> {
await this.ensureValidToken();
let body: string;
const headers: HeadersInit = {};
payload.token = this.authToken;
payload.dm_id = this.dm_id;
// 요청 타입에 따라 처리
if (requestType === 'x-www-form-urlencoded') {
headers['Content-Type'] = 'application/x-www-form-urlencoded';
const params = new URLSearchParams();
Object.keys(payload).forEach((key) => params.append(key, payload[key]));
body = params.toString();
} else if (requestType === 'application/json') {
headers['Content-Type'] = 'application/json';
body = JSON.stringify(payload);
} else if (requestType === 'text/xml') {
headers['Content-Type'] = 'text/xml';
body = payload as string; // XML 요청은 미리 문자열로 준비되어 있어야 함
} else {
throw new Error('Unsupported request type');
}
const response = await fetch(`${this.BASE_URL}${endpoint}`, {
method: 'POST',
headers,
body,
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Error ${response.status}: ${errorText}`);
}
const data: T = await response.json();
return data;
}
// 1. 상품 리스트 조회
public async getItemList() {
const endpoint = '/company/item_list.jsp';
const payload = { dm_id: this.dm_id };
return this.makeApiRequest(endpoint, payload, 'x-www-form-urlencoded');
}
// 2. 상품 정보 조회
public async getItemInfo(itemId: string) {
const endpoint = '/company/item_info.jsp';
const payload = { dm_id: this.dm_id, item_id: itemId };
return this.makeApiRequest(endpoint, payload, 'x-www-form-urlencoded');
}
// 4. 상품 주문
public async orderProduct(
orderId: string,
orderData: Array<{ prd_num: number; amt: number; sale_price: number; m_time: string }>,
customerInfo: { name: string; phone: string; address: string },
) {
const endpoint = 'company/order.jsp';
const payload = {
token: this.authToken,
dm_id: this.dm_id,
ord_id: orderId,
ord_data: orderData, // 주문 데이터 (JSON 형식)
customer_info: customerInfo, // 고객 정보 (JSON 형식)
};
return this.makeApiRequest(endpoint, payload, 'x-www-form-urlendcoded');
}
// 5.주문 내역 조회
public async getOrderHistory(orderId: string) {
const endpoint = '/company/order_list.jsp';
const payload = { dm_id: this.dm_id, ord_id: orderId };
return this.makeApiRequest(endpoint, payload, 'x-www-form-urlencoded');
}
// 6.주문자 정보 수정
public async modifyCustomerInfo(orderId: string, customerData: any) {
const endpoint = '/company/customer_modify.jsp';
const payload = {
dm_id: this.dm_id,
ord_id: orderId,
...customerData,
};
return this.makeApiRequest(endpoint, payload, 'x-www-form-urlencoded');
}
// 7. 주문 정보 수정
public async modifyOrder(
orderId: string,
orderData: Array<{ prd_num: number; amt: number; sale_price: number; m_time: string }>,
) {
const endpoint = '/company/order_prd_modify.jsp';
const payload = {
token: this.authToken,
dm_id: this.dm_id,
ord_id: orderId,
ord_data: orderData,
};
return this.makeApiRequest(endpoint, payload, 'application/json');
}
// 8. 주문취소
public async cancelOrder(orderId: string) {
const endpoint = '/company/order_cancel.jsp';
const payload = { dm_id: this.dm_id, ord_id: orderId };
return this.makeApiRequest(endpoint, payload, 'application/json');
}
// 9. 배송상태조회
public async checkDeliveryStatus(orderId: string) {
const endpoint = '/company/dlvy_status.jsp';
const payload = { dm_id: this.dm_id, ord_id: orderId };
return this.makeApiRequest(endpoint, payload, 'application/json');
}
// 10. 기간별 발주내역 조회
public async getOrderHistoryByPeriod(startDate: string, endDate: string) {
const endpoint = '/orderlist_by_period.jsp';
const payload = {
dm_id: this.dm_id,
sdate: startDate, // 조회 시작일
edate: endDate, // 조회 종료일
};
return this.makeApiRequest(endpoint, payload, 'application/json');
}
// 11. 배송사조회
public async getDeliveryCompanies() {
const endpoint = '/company/dlvy_corp_list.jsp';
const payload = { dm_id: this.dm_id };
return this.makeApiRequest(endpoint, payload, 'application/json');
}
}
const cosmaxService = new CosmaxService('418', 5, 27);
export default cosmaxService;
import * as z from 'zod';
// 각 서비스의 입력/출력 스키마 정의
export const CosmaxServicesResults = {
// 1. 상품 리스트 조회
getItemList: {
name: '/company/item_list.jsp',
inputParams: z.object({
token: z.string(),
dm_id: z.number().int(),
}),
outputParams: z.object({
result: z.enum(['00', '99']),
message: z.string(),
data: z.array(
z.object({
cit_id: z.number(),
cit_name: z.string(),
cit_summary: z.string(),
cit_market_price: z.number(),
cit_supply_price: z.number(),
cit_file_1: z.string(),
cit_updated_datetime: z.string(),
cit_unit: z.string(),
cit_unit_per_count: z.number(),
cit_unit_per_day_count: z.number(),
})
),
}),
},
// 2. 상품 정보 조회
getItemInfo: {
name: '/company/item_info.jsp',
inputParams: z.object({
token: z.string(),
dm_id: z.number(),
cit_id: z.number(),
}),
outputParams: z.object({
result: z.enum(['00', '99']),
message: z.string(),
data: z.object({
cit_id: z.number(),
cit_name: z.string(),
cit_summary: z.string(),
cit_market_price: z.number(),
cit_supply_price: z.number(),
cit_file_1: z.string(),
cit_updated_datetime: z.string(),
cit_unit: z.string(),
cit_unit_per_count: z.number(),
cit_unit_per_day_count: z.number(),
}),
}),
},
// 4. 상품 주문
orderProduct: {
name: '/company/order.jsp',
inputParams: z.object({
token: z.string(),
dm_id: z.number(),
mem_id: z.number(),
str_id: z.number(),
mem_name: z.string(),
mem_addr1: z.string(),
mem_addr2: z.string(),
mem_postno: z.string(),
mem_phone: z.string(),
mem_email: z.string(),
mem_memo: z.string().optional(),
oc_ord_id: z.string(),
ppiu: z.enum(['Y', 'N']),
ord_data: z.array(
z.object({
prd_num: z.number(),
amt: z.number(),
sale_price: z.number(),
m_time: z.string().min(4).max(4),
})
),
}),
outputParams: z.object({
ord_id: z.string(),
result: z.enum(['00', '99']),
message: z.string(),
}),
},
// 5. 주문 내역 조회
getOrderHistory: {
name: '/company/order_list.jsp',
inputParams: z.object({
token: z.string(),
dm_id: z.number(),
ord_id: z.string(),
}),
outputParams: z.object({
result: z.enum(['00', '99']),
message: z.string(),
order_header: z.object({
mem_id: z.number(),
str_id: z.number(),
name: z.string(),
addr1: z.string(),
addr2: z.string().optional(),
email: z.string(),
phone: z.string(),
memo: z.string().optional(),
amount: z.string(),
}),
order_detail_list: z.array(
z.object({
cod_id: z.number(),
cit_id: z.number(),
cod_title: z.string(),
cit_price: z.number(),
cod_count: z.number(),
cod_unit: z.string(),
cod_unit_per_count: z.number(),
cod_m_time: z.string(),
})
),
}),
},
// 6. 주문자 정보 수정
modifyCustomerInfo: {
name: '/company/customer_modify.jsp',
inputParams: z.object({
token: z.string(),
dm_id: z.number(),
ord_id: z.string(),
mem_name: z.string().optional(),
mem_addr1: z.string().optional(),
mem_addr2: z.string().optional(),
mem_postno: z.string().optional(),
mem_phone: z.string().optional(),
mem_email: z.string().optional(),
mem_memo: z.string().optional(),
}),
outputParams: z.object({
result: z.enum(['00', '99']),
message: z.string(),
}),
},
// 7. 주문 정보 수정
modifyOrder: {
name: '/company/order_prd_modify.jsp',
inputParams: z.object({
token: z.string(),
dm_id: z.number(),
ord_id: z.string(),
ord_data: z.array(
z.object({
prd_num: z.number(),
amt: z.number(),
sale_price: z.number(),
m_time: z.string(),
})
),
}),
outputParams: z.object({
ord_id: z.string(),
result: z.enum(['00', '99']),
message: z.string(),
}),
},
// 8. 주문 취소
cancelOrder: {
name: '/company/order_cancel.jsp',
inputParams: z.object({
token: z.string(),
dm_id: z.number(),
ord_id: z.string(),
}),
outputParams: z.object({
ord_id: z.string(),
result: z.enum(['00', '99']),
message: z.string(),
}),
},
// 9. 배송 상태 조회
checkDeliveryStatus: {
name: '/company/dlvy_status.jsp',
inputParams: z.object({
token: z.string(),
dm_id: z.number(),
ord_id: z.string(),
}),
outputParams: z.object({
data: z.object({
dlvy_status: z.number(),
dlvy_corp: z.string(),
dlvy_invoice: z.string(),
dlvy_traceUrl: z.string().url(),
}),
result: z.enum(['00', '99']),
message: z.string(),
}),
},
// 10. 기간별 발주 내역 조회
getOrderHistoryByPeriod: {
name: '/company/orderlist_by_period.jsp',
inputParams: z.object({
token: z.string(),
dm_id: z.number(),
sdate: z.string(),
edate: z.string(),
}),
outputParams: z.object({
result: z.enum(['00', '99']),
message: z.string(),
data: z.array(
z.object({
ord_id: z.string(),
date: z.string(),
name: z.string(),
phone: z.string(),
addr1: z.string(),
addr2: z.string().optional(),
sum: z.number(),
dlvy_status: z.number(),
dlvy_corp: z.string(),
invoice: z.string(),
})
),
}),
},
// 11. 배송사 조회
getDeliveryCompanies: {
name: '/company/dlvy_corp_list.jsp',
inputParams: z.object({
token: z.string(),
dm_id: z.number(),
}),
outputParams: z.object({
result: z.enum(['00', '99']),
message: z.string(),
data: z.array(
z.object({
dlvy_id: z.number(),
dlvy_name: z.string(),
dlvy_track_url: z.string(),
dlvy_is_use: z.enum(['Y', 'N']),
})
),
}),
},
};