Celeskry commited on
Commit
e4647de
·
verified ·
1 Parent(s): 8d003a6

Update app/gm_crate.py

Browse files
Files changed (1) hide show
  1. app/gm_crate.py +109 -59
app/gm_crate.py CHANGED
@@ -1,6 +1,7 @@
1
  # app/gm_crate.py
2
  import os
3
  import base64
 
4
  from email.utils import formataddr
5
  from email.message import EmailMessage
6
  from google.oauth2.credentials import Credentials
@@ -10,6 +11,7 @@ from datetime import datetime
10
 
11
  class GmailLogic:
12
  def __init__(self):
 
13
  self.client_id = os.getenv("GMAIL_CLIENT_ID")
14
  self.client_secret = os.getenv("GMAIL_CLIENT_SECRET")
15
  self.refresh_token = os.getenv("GMAIL_REFRESH_TOKEN")
@@ -17,6 +19,7 @@ class GmailLogic:
17
  self.display_name = "Celeste Store"
18
 
19
  def get_service(self):
 
20
  creds = Credentials(
21
  None,
22
  refresh_token=self.refresh_token,
@@ -24,9 +27,15 @@ class GmailLogic:
24
  client_id=self.client_id,
25
  client_secret=self.client_secret,
26
  )
27
- creds.refresh(Request())
 
28
  return build('gmail', 'v1', credentials=creds)
29
 
 
 
 
 
 
30
  async def send_order_email(
31
  self,
32
  to_email: str,
@@ -38,6 +47,7 @@ class GmailLogic:
38
  total_price: str,
39
  from_name: str = "Celeste Store"
40
  ):
 
41
  try:
42
  service = self.get_service()
43
  now = datetime.now().strftime("%d/%m/%Y")
@@ -61,91 +71,131 @@ class GmailLogic:
61
  <html lang="vi">
62
  <head>
63
  <meta charset="UTF-8">
64
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
65
  <style>
66
- body {{ margin:0; padding:0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; background:#f8f9fa; color:#333; line-height:1.6; }}
67
  .container {{ max-width:580px; margin:20px auto; background:#ffffff; border-radius:12px; overflow:hidden; box-shadow:0 4px 20px rgba(0,0,0,0.05); }}
68
  .header {{ background:#ffffff; padding:40px 30px 20px; text-align:center; border-bottom:1px solid #eee; }}
69
- .header h1 {{ margin:0; font-size:26px; font-weight:500; color:#111; }}
70
- .header p {{ margin:8px 0 0; color:#666; font-size:15px; }}
71
  .content {{ padding:30px; }}
72
- .greeting {{ font-size:17px; margin-bottom:25px; }}
73
  .order-box {{ background:#f9fafb; padding:25px; border-radius:10px; margin:25px 0; }}
74
- .order-box h2 {{ margin:0 0 20px; font-size:18px; font-weight:600; color:#222; }}
75
- table {{ width:100%; border-collapse:collapse; font-size:15px; }}
76
- td {{ padding:10px 0; border-bottom:1px solid #eee; }}
77
- .label {{ width:40%; color:#555; font-weight:500; }}
78
- .value {{ text-align:right; font-weight:500; }}
79
- .total-row td {{ padding:15px 0 5px; font-size:18px; border:none; }}
80
- .total-row .label {{ font-weight:600; color:#111; }}
81
  .total-row .value {{ font-weight:700; color:#e91e63; font-size:20px; }}
82
- .products h3 {{ margin:30px 0 15px; font-size:17px; color:#222; }}
83
- .support {{ margin:30px 0 0; font-size:15px; color:#555; text-align:center; }}
84
- .footer {{ background:#f8f9fa; padding:25px; text-align:center; font-size:13px; color:#888; border-top:1px solid #eee; }}
85
- a {{ color:#e91e63; text-decoration:none; }}
86
  </style>
87
  </head>
88
  <body>
89
  <div class="container">
90
- <div class="header">
91
- <h1>ĐƠN HÀNG ĐÃ ĐẶT THÀNH CÔNG</h1>
92
- <p>Cảm ơn bạn đã ủng hộ shop nha ♡</p>
93
- </div>
94
-
95
  <div class="content">
96
- <p class="greeting">Chào <strong>{customer_name}</strong>,</p>
97
- <p>Chúng mình đã nhận được đơn hàng của bạn rồi! Đang kiểm tra và chuẩn bị gói hàng thật xinh xắn cho bạn đây~</p>
98
-
99
  <div class="order-box">
100
- <h2>Thông tin đơn hàng</h2>
101
  <table>
102
- <tr>
103
- <td class="label">Mã đơn hàng</td>
104
- <td class="value"><strong>#{order_id}</strong></td>
105
- </tr>
106
- <tr>
107
- <td class="label">Ngày đặt</td>
108
- <td class="value">{now}</td>
109
- </tr>
110
- <tr>
111
- <td class="label">Trạng thái</td>
112
- <td class="value"><strong style="color:#10b981;">{status}</strong></td>
113
- </tr>
114
  </table>
115
-
116
- <h3 class="products">Sản phẩm</h3>
117
  <table>
118
  {product_rows_html}
119
- <tr class="total-row">
120
- <td class="label">Tổng tiền</td>
121
- <td class="value">{total_price}</td>
122
- </tr>
123
  </table>
124
  </div>
125
-
126
- <p class="support">Nếu cần hỗ trợ gì thì cứ nhắn shop ngay nhé:<br>
127
- Hotline: 0909 123 456 | Email: support@yourshop.vn</p>
128
-
129
- <p style="text-align:center; margin-top:35px; color:#777; font-style:italic;">
130
- Hẹn gặp bạn sớm với đơn hàng xinh xắn này nha~ 💕
131
- </p>
132
- </div>
133
-
134
- <div class="footer">
135
- <p>Celeste Store • Trà Vinh • Việt Nam</p>
136
- <p>© 2026 — Gửi đến bạn những điều nhỏ bé nhưng ấm áp</p>
137
  </div>
 
138
  </div>
139
  </body>
140
  </html>
141
  """
142
-
143
  message.set_content(f"Xác nhận đơn hàng #{order_id}")
144
  message.add_alternative(html_content, subtype='html')
 
 
 
 
 
145
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
147
  service.users().messages().send(userId="me", body={'raw': raw_message}).execute()
148
 
149
- return {"ok": True, "message": "Email sent successfully!"}
150
  except Exception as e:
151
- return {"ok": False, "error": str(e)}
 
1
  # app/gm_crate.py
2
  import os
3
  import base64
4
+ import uuid
5
  from email.utils import formataddr
6
  from email.message import EmailMessage
7
  from google.oauth2.credentials import Credentials
 
11
 
12
  class GmailLogic:
13
  def __init__(self):
14
+ # Các thông tin này lấy từ biến môi trường (Environment Variables)
15
  self.client_id = os.getenv("GMAIL_CLIENT_ID")
16
  self.client_secret = os.getenv("GMAIL_CLIENT_SECRET")
17
  self.refresh_token = os.getenv("GMAIL_REFRESH_TOKEN")
 
19
  self.display_name = "Celeste Store"
20
 
21
  def get_service(self):
22
+ """Khởi tạo kết nối với Gmail API"""
23
  creds = Credentials(
24
  None,
25
  refresh_token=self.refresh_token,
 
27
  client_id=self.client_id,
28
  client_secret=self.client_secret,
29
  )
30
+ if not creds.valid:
31
+ creds.refresh(Request())
32
  return build('gmail', 'v1', credentials=creds)
33
 
34
+ def generate_random_order_id(self):
35
+ """Tạo mã đơn hàng ngẫu nhiên định dạng CS-2026-XXXX (4 ký tự cuối random)"""
36
+ random_suffix = uuid.uuid4().hex[:4].upper()
37
+ return f"CS-2026-{random_suffix}"
38
+
39
  async def send_order_email(
40
  self,
41
  to_email: str,
 
47
  total_price: str,
48
  from_name: str = "Celeste Store"
49
  ):
50
+ """Gửi email xác nhận khi khách vừa đặt hàng"""
51
  try:
52
  service = self.get_service()
53
  now = datetime.now().strftime("%d/%m/%Y")
 
71
  <html lang="vi">
72
  <head>
73
  <meta charset="UTF-8">
 
74
  <style>
75
+ body {{ margin:0; padding:0; font-family: -apple-system, sans-serif; background:#f8f9fa; color:#333; }}
76
  .container {{ max-width:580px; margin:20px auto; background:#ffffff; border-radius:12px; overflow:hidden; box-shadow:0 4px 20px rgba(0,0,0,0.05); }}
77
  .header {{ background:#ffffff; padding:40px 30px 20px; text-align:center; border-bottom:1px solid #eee; }}
 
 
78
  .content {{ padding:30px; }}
 
79
  .order-box {{ background:#f9fafb; padding:25px; border-radius:10px; margin:25px 0; }}
80
+ table {{ width:100%; border-collapse:collapse; }}
 
 
 
 
 
 
81
  .total-row .value {{ font-weight:700; color:#e91e63; font-size:20px; }}
82
+ .footer {{ background:#f8f9fa; padding:25px; text-align:center; font-size:13px; color:#888; }}
 
 
 
83
  </style>
84
  </head>
85
  <body>
86
  <div class="container">
87
+ <div class="header"><h1>ĐƠN HÀNG ĐÃ ĐẶT THÀNH CÔNG</h1><p>Cảm ơn bạn đã ủng hộ shop nha ♡</p></div>
 
 
 
 
88
  <div class="content">
89
+ <p>Chào <strong>{customer_name}</strong>, chúng mình đã nhận được đơn hàng của bạn!</p>
 
 
90
  <div class="order-box">
 
91
  <table>
92
+ <tr><td>Mã đơn hàng</td><td style="text-align:right"><strong>#{order_id}</strong></td></tr>
93
+ <tr><td>Ngày đặt</td><td style="text-align:right">{now}</td></tr>
94
+ <tr><td>Trạng thái</td><td style="text-align:right"><strong style="color:#10b981;">{status}</strong></td></tr>
 
 
 
 
 
 
 
 
 
95
  </table>
96
+ <h3 style="margin-top:20px;">Sản phẩm</h3>
 
97
  <table>
98
  {product_rows_html}
99
+ <tr class="total-row"><td><strong>Tổng tiền</strong></td><td style="text-align:right" class="value">{total_price}</td></tr>
 
 
 
100
  </table>
101
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
102
  </div>
103
+ <div class="footer"><p>Celeste Store • Trà Vinh • Việt Nam</p></div>
104
  </div>
105
  </body>
106
  </html>
107
  """
 
108
  message.set_content(f"Xác nhận đơn hàng #{order_id}")
109
  message.add_alternative(html_content, subtype='html')
110
+ raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
111
+ service.users().messages().send(userId="me", body={'raw': raw_message}).execute()
112
+ return {"ok": True, "order_id": order_id}
113
+ except Exception as e:
114
+ return {"ok": False, "error": str(e)}
115
 
116
+ async def send_complete_email(
117
+ self,
118
+ to_email: str,
119
+ customer_name: str,
120
+ order_id: str,
121
+ product_name: str,
122
+ price: str,
123
+ tk: str,
124
+ mk: str
125
+ ):
126
+ """Gửi email khi đơn hàng đã Hoàn Thành kèm thông tin tài khoản"""
127
+ try:
128
+ service = self.get_service()
129
+ date_now = datetime.now().strftime("%d/%m/%Y")
130
+
131
+ message = EmailMessage()
132
+ message['To'] = to_email
133
+ message['From'] = formataddr((self.display_name, self.user_email))
134
+ message['Subject'] = f"Đơn hàng #{order_id} đã hoàn thành"
135
+
136
+ html_content = f"""
137
+ <!DOCTYPE html>
138
+ <html lang="vi">
139
+ <head>
140
+ <meta charset="UTF-8">
141
+ <style>
142
+ body{{margin:0;padding:0;background:#f3f4f6;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial;color:#333}}
143
+ .container{{max-width:560px;margin:20px auto;background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 6px 20px rgba(0,0,0,.05)}}
144
+ .header{{text-align:center;padding:35px 20px;border-bottom:1px solid #eee}}
145
+ .header h1{{margin:0;font-size:24px;color:#111}}
146
+ .content{{padding:30px}}
147
+ .order-box{{background:#f9fafb;border-radius:10px;padding:20px;border:1px solid #eee;margin-bottom:25px}}
148
+ table{{width:100%;border-collapse:collapse;font-size:14px}}
149
+ td{{padding:10px 0;border-bottom:1px solid #eee}}
150
+ .label{{color:#666}}
151
+ .value{{text-align:right;font-weight:500}}
152
+ .status{{color:#10b981;font-weight:600}}
153
+ .total{{font-size:18px;font-weight:700;color:#e91e63;border:none}}
154
+ .account-box{{background:#f5f6fa;border:1px solid #e5e7eb;border-radius:10px;padding:18px;margin-top:10px}}
155
+ .account-title{{font-size:14px;color:#666;font-weight:600;margin-bottom:10px}}
156
+ .footer{{text-align:center;background:#f3f4f6;padding:22px;font-size:13px;color:#888;border-top:1px solid #eee}}
157
+ </style>
158
+ </head>
159
+ <body>
160
+ <div class="container">
161
+ <div class="header">
162
+ <h1>ĐƠN HÀNG HOÀN THÀNH</h1>
163
+ <p>Cảm ơn bạn đã mua hàng tại shop ♡</p>
164
+ </div>
165
+ <div class="content">
166
+ <p>Chào <strong>{customer_name}</strong>,</p>
167
+ <p>Đơn hàng của bạn đã được xử lý thành công. Thông tin chi tiết bên dưới:</p>
168
+ <div class="order-box">
169
+ <table>
170
+ <tr><td class="label">Mã đơn hàng</td><td class="value"><strong>#{order_id}</strong></td></tr>
171
+ <tr><td class="label">Ngày</td><td class="value">{date_now}</td></tr>
172
+ <tr><td class="label">Sản phẩm</td><td class="value">{product_name}</td></tr>
173
+ <tr><td class="label">Trạng thái</td><td class="value status">Hoàn Thành</td></tr>
174
+ <tr><td class="label">Tổng tiền</td><td class="value total">{price}</td></tr>
175
+ </table>
176
+ </div>
177
+ <div class="account-box">
178
+ <div class="account-title">Thông tin tài khoản</div>
179
+ <table style="width:100%;">
180
+ <tr><td style="width:90px;color:#777;">Tài khoản</td><td style="font-weight:600;">{tk}</td></tr>
181
+ <tr><td style="color:#777;">Mật khẩu</td><td style="font-weight:600;">{mk}</td></tr>
182
+ </table>
183
+ <div style="margin-top:14px;padding:10px;background:#fff;border:1px dashed #ddd;border-radius:6px;font-family:monospace;font-size:13px;word-break:break-all">
184
+ {tk}:{mk}
185
+ </div>
186
+ </div>
187
+ <p style="font-size:13px;color:#777;margin-top:15px;">Lưu ý:<br>1. KHÔNG đăng nhập vào iCloud<br>2. KHÔNG thêm SĐT<br>3. KHÔNG đổi mật khẩu</p>
188
+ </div>
189
+ <div class="footer">Celeste Store • Trà Vinh • Việt Nam<br>© 2026 Celeste Store</div>
190
+ </div>
191
+ </body>
192
+ </html>
193
+ """
194
+ message.set_content(f"Tài khoản đơn hàng #{order_id}")
195
+ message.add_alternative(html_content, subtype='html')
196
  raw_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
197
  service.users().messages().send(userId="me", body={'raw': raw_message}).execute()
198
 
199
+ return {"ok": True}
200
  except Exception as e:
201
+ return {"ok": False, "error": str(e)}