diff --git a/internal/api/handler/payment.go b/internal/api/handler/payment.go
index 0516dec..a33b375 100644
--- a/internal/api/handler/payment.go
+++ b/internal/api/handler/payment.go
@@ -25,10 +25,11 @@ func NewOrderHandler(walletAddress string, orderSrv *services.Order, conversor *
}
type orderReq struct {
- OrderID string `json:"order_id"`
- ClientID string `json:"client_id"`
- Amount float64 `json:"amount"`
- Currency domain.FiatCurrency `json:"currency"`
+ OrderID string `json:"order_id"`
+ ClientID string `json:"client_id"`
+ Amount float64 `json:"amount"`
+ Currency domain.FiatCurrency `json:"currency"`
+ ClientEmail string `json:"client_email"`
}
func (hdl *OrderHandler) Post(c *fiber.Ctx) error {
@@ -42,7 +43,7 @@ func (hdl *OrderHandler) Post(c *fiber.Ctx) error {
return RenderError(c, fmt.Errorf("hdl.conversor.UsdToBtc %w", err), "")
}
- order, err := hdl.orderSrv.NewOrder(c.Context(), req.OrderID, req.ClientID, btcAmount)
+ order, err := hdl.orderSrv.NewOrder(c.Context(), req.OrderID, req.ClientID, req.ClientEmail, btcAmount)
if err != nil {
return RenderError(c, fmt.Errorf("hdl.orderSrv.NewOrder %w", err), "")
}
diff --git a/internal/api/server.go b/internal/api/server.go
index 092cde6..05f4cae 100644
--- a/internal/api/server.go
+++ b/internal/api/server.go
@@ -102,18 +102,22 @@ func (s *RestServer) onNotification(ctx context.Context, notifChan chan domain.N
order.Block = notif.BlockHash
order.Tx = notif.Tx
-
- if err := s.orderSrv.OrderCompleted(ctx, order); err != nil {
+ order, err = s.orderSrv.OrderCompleted(ctx, order)
+ if err != nil {
log.Println("OrderCompleted:", err)
continue
}
// Send email to client and provider
if err := s.mailSrv.SendProviderConfirm(mail.SendOK{
- TxID: order.Tx,
- BlockHash: order.Block,
- DocHash: "",
- To: "doc.Email",
+ Tx: order.Tx,
+ Block: order.Block,
+ Amount: order.Amount,
+ ExplorerUrl: s.btcService.Explorer(order.Tx),
+ CustomerID: order.ClientID,
+ OrderID: order.OrderID,
+ Timestamp: order.PaidAt,
+ To: order.Email,
}); err != nil {
log.Println("error while send confirm email:", err)
continue
diff --git a/internal/domain/order.go b/internal/domain/order.go
index afc38db..19cafee 100644
--- a/internal/domain/order.go
+++ b/internal/domain/order.go
@@ -10,6 +10,7 @@ type Order struct {
ID primitive.ObjectID `bson:"_id" json:"_id"`
OrderID string `json:"order_id"`
ClientID string `json:"client_id"`
+ Email string `json:"email"`
Amount float64 `bson:"amount" json:"amount"`
Tx string `bson:"tx" json:"tx"`
Block string `bson:"block" json:"block"`
diff --git a/internal/platform/mongodb/order/repository.go b/internal/platform/mongodb/order/repository.go
index d9a2a55..0a76b4f 100644
--- a/internal/platform/mongodb/order/repository.go
+++ b/internal/platform/mongodb/order/repository.go
@@ -64,7 +64,7 @@ func (repo *Repo) FromAmount(ctx context.Context, amount float64, timestamp time
return order, nil
}
-func (repo *Repo) OrderCompleted(ctx context.Context, order *domain.Order) error {
+func (repo *Repo) OrderCompleted(ctx context.Context, order *domain.Order) (*domain.Order, error) {
updateOpts, err := repo.collection.UpdateOne(ctx, bson.M{"_id": order.ID},
bson.M{
"tx": order.Tx,
@@ -73,8 +73,8 @@ func (repo *Repo) OrderCompleted(ctx context.Context, order *domain.Order) error
},
)
if err != nil {
- return fmt.Errorf("collection.UpdateOne: %s", err)
+ return nil, fmt.Errorf("collection.UpdateOne: %s", err)
}
log.Printf("OrderCompleted update %+v\n", updateOpts)
- return nil
+ return order, nil
}
diff --git a/internal/services/mail/mail.go b/internal/services/mail/mail.go
index 03f05dc..112adda 100644
--- a/internal/services/mail/mail.go
+++ b/internal/services/mail/mail.go
@@ -31,11 +31,13 @@ type MailService struct {
}
type SendOK struct {
- Price float64
+ Amount float64
ExplorerUrl string
- TxID string
- BlockHash string
- DocHash string
+ Tx string
+ CustomerID string
+ OrderID string
+ Block string
+ Timestamp time.Time
To string
}
@@ -115,10 +117,11 @@ func (m *MailService) SendProviderConfirm(data SendOK) error {
return fmt.Errorf("os.ReadFile: %s", err)
}
template := strings.Replace(string(bts), "{{explorer_url}}", data.ExplorerUrl, -1)
- template = strings.Replace(template, "{{tx_id}}", data.TxID, -1)
- template = strings.Replace(template, "{{block_hash}}", data.BlockHash, -1)
- template = strings.Replace(template, "{{doc_hash}}", data.DocHash, -1)
- template = strings.Replace(template, "{{support_email}}", m.from, -1)
+ template = strings.Replace(template, "{{customer_id}}", data.CustomerID, -1)
+ template = strings.Replace(template, "{{order_id}}", data.OrderID, -1)
+ template = strings.Replace(template, "{{tx}}", data.Tx, -1)
+ template = strings.Replace(template, "{{block}}", data.Block, -1)
+ template = strings.Replace(template, "{{timestamp}}", data.Timestamp.Format(time.RFC3339), -1)
msg := []byte(m.messageWithHeaders(okSubject, data.To, template))
return m.send(data.To, msg)
}
@@ -129,10 +132,11 @@ func (m *MailService) SendClientConfirm(data SendOK) error {
return fmt.Errorf("os.ReadFile: %s", err)
}
template := strings.Replace(string(bts), "{{explorer_url}}", data.ExplorerUrl, -1)
- template = strings.Replace(template, "{{tx_id}}", data.TxID, -1)
- template = strings.Replace(template, "{{block_hash}}", data.BlockHash, -1)
- template = strings.Replace(template, "{{doc_hash}}", data.DocHash, -1)
- template = strings.Replace(template, "{{support_email}}", m.from, -1)
+ template = strings.Replace(template, "{{customer_id}}", data.CustomerID, -1)
+ template = strings.Replace(template, "{{order_id}}", data.OrderID, -1)
+ template = strings.Replace(template, "{{tx}}", data.Tx, -1)
+ template = strings.Replace(template, "{{block}}", data.Block, -1)
+ template = strings.Replace(template, "{{timestamp}}", data.Timestamp.Format(time.RFC3339), -1)
msg := []byte(m.messageWithHeaders(okSubject, data.To, template))
return m.send(data.To, msg)
}
@@ -144,9 +148,8 @@ func (m *MailService) SendFail(data SendOK) error {
return fmt.Errorf("os.ReadFile: %s", err)
}
template := strings.Replace(string(bts), "{{explorer_url}}", data.ExplorerUrl, -1)
- template = strings.Replace(template, "{{tx_id}}", data.TxID, -1)
- template = strings.Replace(template, "{{block_hash}}", data.BlockHash, -1)
- template = strings.Replace(template, "{{doc_hash}}", data.DocHash, -1)
+ template = strings.Replace(template, "{{tx_id}}", data.Tx, -1)
+ template = strings.Replace(template, "{{block_hash}}", data.Block, -1)
template = strings.Replace(template, "{{support_email}}", m.from, -1)
// TODO: Alert client too
msg := []byte(m.messageWithHeaders(okSubject, data.To, template))
diff --git a/internal/services/mail/mail_test.go b/internal/services/mail/mail_test.go
index 2fd0294..0ca8f69 100644
--- a/internal/services/mail/mail_test.go
+++ b/internal/services/mail/mail_test.go
@@ -3,6 +3,7 @@ package mail
import (
"net/smtp"
"testing"
+ "time"
"gitea.urkob.com/urko/btc-pay-checker/kit"
"gitea.urkob.com/urko/btc-pay-checker/kit/cfg"
@@ -29,9 +30,13 @@ func init() {
func Test_mailService_SendOK(t *testing.T) {
dto := SendOK{
- Price: 10.2,
+ Amount: 12.0,
ExplorerUrl: "test",
- TxID: "test-hash",
+ Tx: "test-hash",
+ CustomerID: "client",
+ OrderID: "order",
+ Block: "block",
+ Timestamp: time.Now(),
To: config.MailTo,
}
@@ -41,9 +46,13 @@ func Test_mailService_SendOK(t *testing.T) {
func Test_mailService_SendConfirm(t *testing.T) {
dto := SendOK{
+ Amount: 12.0,
ExplorerUrl: "test",
- TxID: "test-hash",
- BlockHash: "block-hash",
+ Tx: "test-hash",
+ CustomerID: "client",
+ OrderID: "order",
+ Block: "block",
+ Timestamp: time.Now(),
To: config.MailTo,
}
diff --git a/internal/services/mail/templates/client_confirm.html b/internal/services/mail/templates/client_confirm.html
index 17498c8..eea6eb5 100644
--- a/internal/services/mail/templates/client_confirm.html
+++ b/internal/services/mail/templates/client_confirm.html
@@ -1 +1,51 @@
-TODO:
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
Dear Customer,
+
We are pleased to inform you that we have received your Bitcoin payment. Here are the details of the transaction:
+
Transaction ID: {{tx}}
+
Block ID: {{block}}
+
Timestamp: {{timestamp}}
+
You can view the transaction details at the following URL: {{explorer_url}}
+
Thank you for your payment!
+
+
+
+
+
diff --git a/internal/services/mail/templates/provider_confirm.html b/internal/services/mail/templates/provider_confirm.html
index 17498c8..8c87818 100644
--- a/internal/services/mail/templates/provider_confirm.html
+++ b/internal/services/mail/templates/provider_confirm.html
@@ -1 +1,53 @@
-TODO:
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
Dear Supplier,
+
We are pleased to inform you that we have received a Bitcoin payment for a recent order. Here are the details of the transaction:
+
Customer ID: {{customer_id}}
+
Order ID: {{order_id}}
+
Transaction ID: {{tx}}
+
Block ID: {{block}}
+
Timestamp: {{timestamp}}
+
You can view the transaction details at the following URL: {{explorer_url}}
+
We will proceed with the order fulfillment as per our agreement. Thank you for your cooperation!
+
+
+
+
+
diff --git a/internal/services/order.go b/internal/services/order.go
index 2ea86a1..4bb2b53 100644
--- a/internal/services/order.go
+++ b/internal/services/order.go
@@ -28,16 +28,18 @@ func (o *Order) WithExpiration(expiration time.Duration) *Order {
return o
}
-func (o *Order) NewOrder(ctx context.Context, OrderID string, ClientID string, amount float64) (*domain.Order, error) {
+func (o *Order) NewOrder(ctx context.Context, orderID, clientID, email string, amount float64) (*domain.Order, error) {
order := domain.Order{
ID: primitive.NewObjectID(),
- OrderID: OrderID,
- ClientID: ClientID,
+ OrderID: orderID,
+ ClientID: clientID,
Amount: amount,
PaidAt: time.Time{},
CreatedAt: time.Now(),
ExpiresAt: time.Now().Add(o.expiration),
+ Email: email,
}
+
_, err := o.repo.Insert(ctx, &order)
if err != nil {
return nil, err
@@ -49,6 +51,6 @@ func (o *Order) FromAmount(ctx context.Context, amount float64, timestamp time.T
return o.repo.FromAmount(ctx, amount, timestamp)
}
-func (o *Order) OrderCompleted(ctx context.Context, order *domain.Order) error {
+func (o *Order) OrderCompleted(ctx context.Context, order *domain.Order) (*domain.Order, error) {
return o.repo.OrderCompleted(ctx, order)
}