update
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package customer
|
||||
|
||||
import (
|
||||
"context"
|
||||
errors2 "enaklo-pos-be/internal/common/errors"
|
||||
"enaklo-pos-be/internal/common/logger"
|
||||
"enaklo-pos-be/internal/common/mycontext"
|
||||
"enaklo-pos-be/internal/constants"
|
||||
@@ -8,7 +10,9 @@ import (
|
||||
"enaklo-pos-be/internal/utils"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
@@ -16,26 +20,35 @@ type Repository interface {
|
||||
FindByID(ctx mycontext.Context, id int64) (*entity.Customer, error)
|
||||
FindByPhone(ctx mycontext.Context, phone string) (*entity.Customer, error)
|
||||
FindByEmail(ctx mycontext.Context, email string) (*entity.Customer, error)
|
||||
AddPoints(ctx mycontext.Context, id int64, points int) error
|
||||
AddPoints(ctx mycontext.Context, id int64, points int, reference string) error
|
||||
FindSequence(ctx mycontext.Context, partnerID int64) (int64, error)
|
||||
GetAllCustomers(ctx mycontext.Context, req entity.MemberSearch) (entity.MemberList, int, error)
|
||||
VerifyOTP(ctx mycontext.Context, verificationHash string, otpCode string) (int64, error)
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
ResolveCustomer(ctx mycontext.Context, req *entity.CustomerResolutionRequest) (int64, error)
|
||||
AddPoints(ctx mycontext.Context, customerID int64, points int) error
|
||||
AddPoints(ctx mycontext.Context, customerID int64, points int, reference string) error
|
||||
GetCustomer(ctx mycontext.Context, id int64) (*entity.Customer, error)
|
||||
CustomerCheck(ctx mycontext.Context, req *entity.CustomerResolutionRequest) (*entity.CustomerCheckResponse, error)
|
||||
GetAllCustomers(ctx mycontext.Context, req *entity.MemberSearch) (*entity.MemberList, int, error)
|
||||
RegistrationMember(ctx mycontext.Context, req *entity.Customer) (*entity.Customer, error)
|
||||
VerifyOTP(ctx mycontext.Context, verificationID, otpCode string) error
|
||||
}
|
||||
|
||||
type EmailService interface {
|
||||
SendEmailTransactional(ctx context.Context, param entity.SendEmailNotificationParam) error
|
||||
}
|
||||
|
||||
type customerSvc struct {
|
||||
repo Repository
|
||||
repo Repository
|
||||
notification EmailService
|
||||
}
|
||||
|
||||
func New(repo Repository) Service {
|
||||
func New(repo Repository, notification EmailService) Service {
|
||||
return &customerSvc{
|
||||
repo: repo,
|
||||
repo: repo,
|
||||
notification: notification,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,12 +119,68 @@ func (s *customerSvc) ResolveCustomer(ctx mycontext.Context, req *entity.Custome
|
||||
return customer.ID, nil
|
||||
}
|
||||
|
||||
func (s *customerSvc) AddPoints(ctx mycontext.Context, customerID int64, points int) error {
|
||||
func (s *customerSvc) RegistrationMember(ctx mycontext.Context, req *entity.Customer) (*entity.Customer, error) {
|
||||
if req.Email == "" && req.PhoneNumber == "" {
|
||||
return nil, errors2.ErrorPhoneNumberEmailIsRequired
|
||||
}
|
||||
|
||||
if req.PhoneNumber != "" {
|
||||
customer, err := s.repo.FindByPhone(ctx, req.PhoneNumber)
|
||||
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||
return nil, errors2.ErrorInternalServer
|
||||
}
|
||||
|
||||
if customer != nil {
|
||||
return nil, errors2.ErrorPhoneNumberIsAlreadyRegistered
|
||||
}
|
||||
}
|
||||
|
||||
if req.Email != "" {
|
||||
customer, err := s.repo.FindByEmail(ctx, req.Email)
|
||||
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||
return nil, errors2.ErrorInternalServer
|
||||
}
|
||||
|
||||
if customer != nil {
|
||||
return nil, errors2.ErrorEmailIsAlreadyRegistered
|
||||
}
|
||||
}
|
||||
|
||||
newCustomer := &entity.Customer{
|
||||
Name: req.Name,
|
||||
Email: req.Email,
|
||||
Phone: req.PhoneNumber,
|
||||
CreatedAt: constants.TimeNow(),
|
||||
UpdatedAt: constants.TimeNow(),
|
||||
BirthDate: req.BirthDate,
|
||||
Password: req.HashedPassword(),
|
||||
}
|
||||
|
||||
customer, err := s.repo.Create(ctx, newCustomer)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to create customer", zap.Error(err))
|
||||
return nil, errors2.ErrorInternalServer
|
||||
}
|
||||
|
||||
errs := s.sendRegistrationOTP(ctx, &entity.MemberRegistration{
|
||||
Name: customer.Name,
|
||||
Email: customer.Email,
|
||||
OTP: customer.OTP,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to send OTP", zap.Error(errs))
|
||||
}
|
||||
|
||||
return customer, nil
|
||||
}
|
||||
|
||||
func (s *customerSvc) AddPoints(ctx mycontext.Context, customerID int64, points int, reference string) error {
|
||||
if points <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := s.repo.AddPoints(ctx, customerID, points)
|
||||
err := s.repo.AddPoints(ctx, customerID, points, reference)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to add points to customer")
|
||||
}
|
||||
@@ -202,3 +271,75 @@ func (s *customerSvc) GetAllCustomers(ctx mycontext.Context, req *entity.MemberS
|
||||
|
||||
return &customers, totalCount, nil
|
||||
}
|
||||
|
||||
func (s *customerSvc) sendRegistrationOTP(
|
||||
ctx mycontext.Context,
|
||||
registration *entity.MemberRegistration,
|
||||
) error {
|
||||
emailData := map[string]interface{}{
|
||||
"UserName": registration.Name,
|
||||
"OTPCode": registration.OTP,
|
||||
}
|
||||
|
||||
err := s.notification.SendEmailTransactional(ctx, entity.SendEmailNotificationParam{
|
||||
Sender: "noreply@enaklo.co.id",
|
||||
Recipient: registration.Email,
|
||||
Subject: "Enaklo - Registration Verification Code",
|
||||
TemplateName: "member_registration_otp",
|
||||
TemplatePath: "templates/member_registration_otp.html",
|
||||
Data: emailData,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *customerSvc) VerifyOTP(ctx mycontext.Context, verificationID, otpCode string) error {
|
||||
customerID, err := s.repo.VerifyOTP(ctx, verificationID, otpCode)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "verification failed")
|
||||
}
|
||||
|
||||
customer, _ := s.repo.FindByID(ctx, customerID)
|
||||
|
||||
go func(customer *entity.Customer) {
|
||||
newCtx := context.Background()
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Printf("Recovered from panic in sendWelcomeEmail: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
s.sendWelcomeEmail(newCtx, customer)
|
||||
}(customer)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *customerSvc) sendWelcomeEmail(
|
||||
ctx context.Context,
|
||||
customer *entity.Customer,
|
||||
) error {
|
||||
|
||||
welcomeData := map[string]interface{}{
|
||||
"UserName": customer.Name,
|
||||
"MemberID": customer.CustomerID,
|
||||
"PointsName": "EnakPoint",
|
||||
"PointsBalance": customer.Points,
|
||||
"RedeemLink": "https://enaklo.co.id/redeem",
|
||||
"CurrentDate": time.Now().Format("01-2006"),
|
||||
}
|
||||
|
||||
return s.notification.SendEmailTransactional(ctx, entity.SendEmailNotificationParam{
|
||||
Sender: "noreply@enaklo.co.id",
|
||||
Recipient: customer.Email,
|
||||
Subject: "Welcome to Enaklo Membership Program",
|
||||
TemplateName: "welcome_member",
|
||||
TemplatePath: "templates/welcome_member.html",
|
||||
Data: welcomeData,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user