summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-05-12 11:32:25 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-05-12 11:32:25 +0000
commit20b1a8e6e39b3adf058b32f1b2e219ee93a9f1c7 (patch)
tree429e0d4c656c365a8cb0a5eb800dd4a4e4f2c152 /lib
parent552c82fa3632965949d56317d8730ac3341f22a4 (diff)
(대표님) 메일 발송 - 언어별 템플릿 추가 및 rfq 알림림
Diffstat (limited to 'lib')
-rw-r--r--lib/mail/sendEmail.ts15
-rw-r--r--lib/mail/templates/po-rfq-invite-en.hbs116
-rw-r--r--lib/mail/templates/po-rfq-invite-ko.hbs86
-rw-r--r--lib/mail/templates/rfq-notification.hbs166
4 files changed, 380 insertions, 3 deletions
diff --git a/lib/mail/sendEmail.ts b/lib/mail/sendEmail.ts
index c4171082..97617e7a 100644
--- a/lib/mail/sendEmail.ts
+++ b/lib/mail/sendEmail.ts
@@ -7,7 +7,9 @@ interface SendEmailOptions {
subject: string;
template: string; // 템플릿 파일명(확장자 제외)
context: Record<string, any>; // 템플릿에 주입할 데이터
- attachments?: { // NodeMailer "Attachment" 타입
+ cc?: string | string[]; // cc 필드 추가 - 단일 이메일 또는 이메일 배열
+ attachments?: {
+ // NodeMailer "Attachment" 타입
filename?: string
path?: string
content?: Buffer | string
@@ -15,7 +17,14 @@ interface SendEmailOptions {
}[]
}
-export async function sendEmail({ to, subject, template, context, attachments = []}: SendEmailOptions) {
+export async function sendEmail({
+ to,
+ subject,
+ template,
+ context,
+ cc, // cc 매개변수 추가
+ attachments = []
+}: SendEmailOptions) {
const { t, i18n } = await useTranslation(context.language ?? "en", "translation");
handlebars.registerHelper("t", function (key: string, options: any) {
@@ -28,9 +37,9 @@ export async function sendEmail({ to, subject, template, context, attachments =
await transporter.sendMail({
from: `"${process.env.Email_From_Name}" <${process.env.Email_From_Address}>`,
to,
+ cc, // cc 필드 추가
subject,
html,
attachments
});
}
-
diff --git a/lib/mail/templates/po-rfq-invite-en.hbs b/lib/mail/templates/po-rfq-invite-en.hbs
new file mode 100644
index 00000000..5b47851c
--- /dev/null
+++ b/lib/mail/templates/po-rfq-invite-en.hbs
@@ -0,0 +1,116 @@
+{{> header logoUrl=logoUrl }}
+
+<h1 style="font-size:28px; line-height:40px; margin-bottom:16px;">
+ SHI RFQ NO. : #{{rfqCode}}
+</h1>
+
+<p style="font-size:16px; line-height:32px; margin-bottom:16px;">
+ Dear Sirs,
+</p>
+
+<p style="font-size:16px; line-height:32px; margin-bottom:16px;">
+ We hope your business continuously will be thriving in the years ahead and we are pleased to send you RFQ for the subject item.
+</p>
+
+<p style="font-size:16px; line-height:32px; margin-bottom:16px;">
+ It would be appreciated if we receive your competitive quotation in compliance with the following terms and conditions
+ by the bid closing date (COB of {{DLDate}})
+ Otherwise we will consider that you have no interest on this RFQ.
+</p>
+
+<div style="margin-bottom:24px;">
+ <h2 style="font-size:20px; margin-bottom:12px;">A. Commercial terms and conditions</h2>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>A-1 Project: {{projectName}} + Option {{projectOption}} (Validity: {{ProjectOptionValidity}})</strong>
+ <br>* Ship's Delivery date('YY.MM.DD): {{DLDate}}
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>A-2 Spec. & Scope of the Supply : See the attached PGS/SGS/POS</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>A-3 Terms of Delivery : {{incoterms}}</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>A-4 Estimated Delivery Date: {{EstimatedDeliveryDate}}</strong>
+ <br>- The delivery date can be adjusted by the buyer's procurement part.
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>A-5 Terms of Payment : {{paymentCondition}}</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>A-6 Warranty Period</strong>
+ <br>The Goods supplied and the works performed under this contract shall be guaranteed for {{warrantyPeriod}} months after vessel's delivery.
+ <br>However, the guaranteed period for repair or replacement shall be extended to {{repairAdditionalPeriod}} months,
+ <br>but total guaranteed period shall not exceed {{totalPeriod}} months after vessel's delivery date.
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>A-7 Others not mentioned here are as per previous contract terms.</strong>
+ </p>
+</div>
+
+<div style="margin-bottom:24px;">
+ <h2 style="font-size:20px; margin-bottom:12px;">B. The following information should be included in the Bidder's quotation.</h2>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>B-1 Detailed and Break-Down price (excluding VAT) for the supplies, the spare parts for start-up & commissioning and documentation.</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>B-2 Deviations, if any, from the Buyer's spec and scope of the supply should be specified on the quotation.</strong>
+ <br>Unless specified herein, the Bidder shall be regarded as fully complying with the buyer's spec. and scope of supply.
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>B-3 The earliest possible date for Technical meeting at Geoje Shipyard</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>B-4 Any suggestions in order for both parties to be competitive shall be suggested, if available.</strong>
+ </p>
+</div>
+
+<div style="margin-bottom:24px;">
+ <h2 style="font-size:20px; margin-bottom:12px;">C. Bid Closing Date : {{deadline}}</h2>
+</div>
+
+<div style="margin-bottom:24px;">
+ <h2 style="font-size:20px; margin-bottom:12px;">D. Buyer's Right</h2>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>D-1 Buyer may select seller which did not submit the lowest bid</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>D-2 Buyer may accept or reject some or all of a price quotation, without obligation to notify any person or entity of such rejection.</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>D-3 and Buyer shall have no obligation to notify a bidder of the final decision of rejecting a bid.</strong>
+ </p>
+</div>
+
+<div style="margin-bottom:24px;">
+ <h2 style="font-size:20px; margin-bottom:12px;">E. Seller's Obligation</h2>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>E-1 Seller shall be liable for all costs incurred in submitting a price quotation.</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>E-2 Under no circumstances will a subcontractor not finally selected as Seller have the right to claim for compensation against Buyer.</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>E-3 Selected Seller on condition of shipowner's approval is not allowed to start work without first obtaining the approval of shipowner,</strong>
+ <br>otherwise Seller has no right to make a claim for compensation.
+ </p>
+</div>
+
+<p style="font-size:16px; line-height:24px; margin-top:16px;">
+ If you have any question, please do not hesitate to contact us.
+</p>
+
+<p style="font-size:16px; line-height:24px; margin-top:16px;">
+ Best regards,
+ <br>OOO / Procurement Manager / oooo@samsung.com
+ <br>SAMSUNG HEAVY INDUSTRIES CO., LTD.
+ <br>80, Jangpyeong 3-ro, Geoje-si, Gyeongsangnam-do, Republic of Korea, 53261
+</p>
+
+<p>
+ <a href="{{loginUrl}}" target="_blank" style="display: inline-block; width: 250px; padding: 12px 20px; background-color: #163CC4; color: #ffffff !important; text-decoration: none; border-radius: 8px; text-align: center; line-height: 28px;">
+ View Quotation
+ </a>
+</p>
+
+{{> footer logoUrl=logoUrl companyName=companyName year=year }} \ No newline at end of file
diff --git a/lib/mail/templates/po-rfq-invite-ko.hbs b/lib/mail/templates/po-rfq-invite-ko.hbs
new file mode 100644
index 00000000..372aadb2
--- /dev/null
+++ b/lib/mail/templates/po-rfq-invite-ko.hbs
@@ -0,0 +1,86 @@
+{{> header logoUrl=logoUrl }}
+
+<h1 style="font-size:28px; line-height:40px; margin-bottom:16px;">
+ SHI RFQ NO. : #{{rfqCode}}
+</h1>
+
+<p style="font-size:16px; line-height:32px; margin-bottom:16px;">
+ 안녕하세요, <strong>Vendor #{{vendorId}}</strong>님.
+</p>
+
+<p style="font-size:16px; line-height:32px; margin-bottom:16px;">
+ 귀사의 일익 번창하심을 기원합니다.
+</p>
+
+<p style="font-size:16px; line-height:32px; margin-bottom:16px;">
+ 표제 품목에 대한 견적을 요청하오니 하기 및 첨부 내용 확인하시어 견적서 및 기술사양서 자료를 eVCP를 통해 제출 바랍니다.
+ 또한, 귀사의 신제품 적용 방안이나, 당사 사양 및 공급 범위에 Deviation이 있는 경우
+ 별도의 견적을 제출하시어 당사에서 적극 검토할 수 있도록 협조 바랍니다.
+ 귀사의 견적은 아래의 견적 마감일 이전에 당사로 제출 되어야하며, 견적 마감일 및 당사의 지연 통보없이 미 제출될 경우에는 대상에서 제외될 수 있습니다.
+</p>
+
+<div style="margin-bottom:24px;">
+ <h2 style="font-size:20px; margin-bottom:12px;">가. 거래조건</h2>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>1) 프로젝트 : {{projectName}} + 옵션 {{projectOption}} (Validity : {{ProjectOptionValidity}})</strong>
+ <br>* 호선별 D/L 일정('YY.MM.DD) : {{DLDate}}
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>2) Spec, & Scope of Supply : 첨부 POS 참조</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>3) Class / Flag : 첨부 POS 참조</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>4) Estimated Delivery Date : {{EstimatedDeliveryDate}}</strong>
+ <br>* 상세 납기는 조선소 스케쥴에 따라 변경될 수 있으며, 당사 조달/현업/생산 부서와 협의하여 결정됨.
+ <br>* 안전보건에 관한 사항을 고려하여 납기(또는 계약기간)의 적정성을 검토하고,
+ <br>안전보건확보를 위해 납기의 조정이 필요한 경우 기간 조정을 신청하시기 바랍니다.
+ <br>* (당사 사업장 내에서 수행하는 작업이 포함된 계약)
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>5) Warranty : 선박 인도 후 {{warrantyPeriod}}개월 시점까지 납품한 "자재" 또는 "용역"이 계약 내용과 동일함을 보증하며,</strong>
+ <br>Repair 시 {{repairAdditionalPeriod}}개월 추가되나, 총 인도 후 {{totalPeriod}}개월을 넘지 않음.
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>6) 견적마감기한 : {{deadline}}</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>7) 대금지급조건 : {{paymentCondition}}</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>8) 기타 일반사항은 삼성중공업 표준하도급기본계약서, 안전보건관리 약정서 및 자재 안전 납품/하역을 위한 표준규정에 준함.</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>9) 유의사항</strong>
+ <br>- 발주자는 최저가 견적을 제출하지 않은 협력사를 선정할 수 있으며,
+ <br> 견적의 일부 또는 전부를 승인하거나 거절할 수 있고 거부하는 경우 별도 통보할 의무가 없다.
+ <br> 또한, 최종 탈락 사실을 통보할 의무도 없다.
+ <br>- 협력사는 견적 제출을 위해 소요되는 비용 일체를 부담하며,
+ <br> 최종 계약자로 선정되지 못한 경우에도 발주자에게 보상을 청구할 수 없다.
+ <br> 또한, 선주 승인조건으로 선정된 협력사는 반드시 선주 승인을 득한 후 작업에 착수하여야 하며,
+ <br> 승인 거절 시 계약은 미 체결, 해제될 수 있고 이 경우 협력사는 어떠한 보상도 청구할 수 없다.
+ </p>
+</div>
+
+<div style="margin-bottom:24px;">
+ <h2 style="font-size:20px; margin-bottom:12px;">나. 견적 내용</h2>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>1) 품목별 단가 및 총액</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>2) 가격 기재(VAT 제외) 견적서 / 가격 미기재 견적서 / 설계 Technical Bid Evaluation(TBE) 자료 제출</strong>
+ </p>
+ <p style="font-size:16px; line-height:24px; margin-bottom:8px;">
+ <strong>3) 당사 PGS, SGS & POS에 대한 Deviation List</strong>
+ <br style="color:red">* 별도 Deviation이 없는 경우 견적서 상에 명기
+ </p>
+</div>
+
+<p>
+ <a href="{{loginUrl}}" target="_blank" style="display: inline-block; width: 250px; padding: 12px 20px; background-color: #163CC4; color: #ffffff !important; text-decoration: none; border-radius: 8px; text-align: center; line-height: 28px;">
+ 견적서 확인하기
+ </a>
+</p>
+
+{{> footer logoUrl=logoUrl companyName=companyName year=year }} \ No newline at end of file
diff --git a/lib/mail/templates/rfq-notification.hbs b/lib/mail/templates/rfq-notification.hbs
new file mode 100644
index 00000000..fc510ad0
--- /dev/null
+++ b/lib/mail/templates/rfq-notification.hbs
@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>{{t "email.rfq.title"}}</title>
+ <style>
+ body {
+ font-family: Arial, sans-serif;
+ line-height: 1.6;
+ color: #333;
+ margin: 0;
+ padding: 0;
+ }
+ .container {
+ max-width: 600px;
+ margin: 0 auto;
+ padding: 20px;
+ }
+ .header {
+ background-color: #1a56db;
+ color: #ffffff;
+ padding: 20px;
+ text-align: center;
+ border-radius: 5px 5px 0 0;
+ }
+ .content {
+ padding: 20px;
+ background-color: #ffffff;
+ border: 1px solid #e5e7eb;
+ border-top: none;
+ border-radius: 0 0 5px 5px;
+ }
+ .footer {
+ text-align: center;
+ margin-top: 20px;
+ font-size: 0.8em;
+ color: #6b7280;
+ }
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ margin-bottom: 20px;
+ }
+ th, td {
+ border: 1px solid #e5e7eb;
+ padding: 12px;
+ text-align: left;
+ }
+ th {
+ background-color: #f3f4f6;
+ }
+ .button {
+ display: inline-block;
+ background-color: #1a56db;
+ color: #ffffff;
+ padding: 12px 24px;
+ text-decoration: none;
+ border-radius: 5px;
+ font-weight: bold;
+ margin-top: 20px;
+ }
+ .section-title {
+ margin-top: 25px;
+ margin-bottom: 10px;
+ font-weight: bold;
+ border-bottom: 1px solid #e5e7eb;
+ padding-bottom: 5px;
+ }
+ </style>
+</head>
+<body>
+ <div class="container">
+ <div class="header">
+ <h1>{{t "email.rfq.notification_title"}}</h1>
+ </div>
+ <div class="content">
+ <p>{{t "email.greeting" name=vendor.user.fullName}},</p>
+
+ <p>{{t "email.rfq.introduction"}}</p>
+
+ <div class="section-title">{{t "email.rfq.details_section"}}</div>
+ <table>
+ <tr>
+ <th>{{t "email.rfq.code_label"}}</th>
+ <td>{{rfq.code}}</td>
+ </tr>
+ <tr>
+ <th>{{t "email.rfq.title_label"}}</th>
+ <td>{{rfq.title}}</td>
+ </tr>
+ <tr>
+ <th>{{t "email.rfq.description_label"}}</th>
+ <td>{{rfq.description}}</td>
+ </tr>
+ <tr>
+ <th>{{t "email.rfq.vendor_label"}}</th>
+ <td>{{vendor.name}}</td>
+ </tr>
+ <tr>
+ <th>{{t "email.rfq.quotation_code_label"}}</th>
+ <td>{{quotationCode}}</td>
+ </tr>
+ <tr>
+ <th>{{t "email.rfq.due_date_label"}}</th>
+ <td>{{rfq.dueDate}}</td>
+ </tr>
+ <tr>
+ <th>{{t "email.rfq.delivery_date_label"}}</th>
+ <td>{{rfq.deliveryDate}}</td>
+ </tr>
+ <tr>
+ <th>{{t "email.rfq.currency_label"}}</th>
+ <td>{{details.currency}}</td>
+ </tr>
+ <tr>
+ <th>{{t "email.rfq.payment_terms_label"}}</th>
+ <td>{{details.paymentTerms}}</td>
+ </tr>
+ <tr>
+ <th>{{t "email.rfq.incoterms_label"}}</th>
+ <td>{{details.incoterms}}</td>
+ </tr>
+ </table>
+
+ <div class="section-title">{{t "email.rfq.items_section"}}</div>
+ <table>
+ <thead>
+ <tr>
+ <th>{{t "email.rfq.item_number"}}</th>
+ <th>{{t "email.rfq.item_description"}}</th>
+ <th>{{t "email.rfq.item_quantity"}}</th>
+ <th>{{t "email.rfq.item_uom"}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#each items}}
+ <tr>
+ <td>{{itemNumber}}</td>
+ <td>{{description}}</td>
+ <td>{{quantity}}</td>
+ <td>{{uom}}</td>
+ </tr>
+ {{/each}}
+ </tbody>
+ </table>
+
+ <p>{{t "email.rfq.action_instructions"}}</p>
+
+ <p style="text-align: center;">
+ <a href="{{systemUrl}}/vendor/quotations/{{quotationCode}}" class="button">
+ {{t "email.rfq.view_button"}}
+ </a>
+ </p>
+
+ <p>{{t "email.rfq.closing"}}</p>
+ <p>{{t "email.rfq.sender_signature" name=sender.fullName}}<br>
+ {{sender.email}}</p>
+ </div>
+ <div class="footer">
+ <p>{{t "email.footer.copyright"}} © {{year}} {{t "email.footer.company_name"}}</p>
+ <p>{{t "email.footer.address"}}</p>
+ </div>
+ </div>
+</body>
+</html> \ No newline at end of file