Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -9,11 +9,16 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"bssapp-backend/auth"
|
||||||
"bssapp-backend/internal/mailer"
|
"bssapp-backend/internal/mailer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sendOrderMarketMailPayload struct {
|
type sendOrderMarketMailPayload struct {
|
||||||
OrderHeaderID string `json:"orderHeaderID"`
|
OrderHeaderID string `json:"orderHeaderID"`
|
||||||
|
Operation string `json:"operation"`
|
||||||
|
DeletedItems []string `json:"deletedItems"`
|
||||||
|
UpdatedItems []string `json:"updatedItems"`
|
||||||
|
AddedItems []string `json:"addedItems"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendOrderMarketMailHandler(pg *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) http.HandlerFunc {
|
func SendOrderMarketMailHandler(pg *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) http.HandlerFunc {
|
||||||
@@ -28,6 +33,11 @@ func SendOrderMarketMailHandler(pg *sql.DB, mssql *sql.DB, ml *mailer.GraphMaile
|
|||||||
http.Error(w, "database not initialized", http.StatusInternalServerError)
|
http.Error(w, "database not initialized", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
claims, ok := auth.GetClaimsFromContext(r.Context())
|
||||||
|
if !ok || claims == nil {
|
||||||
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var payload sendOrderMarketMailPayload
|
var payload sendOrderMarketMailPayload
|
||||||
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||||
@@ -80,14 +90,52 @@ func SendOrderMarketMailHandler(pg *sql.DB, mssql *sql.DB, ml *mailer.GraphMaile
|
|||||||
marketLabel = strings.TrimSpace(marketCode)
|
marketLabel = strings.TrimSpace(marketCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
subject := fmt.Sprintf("Sipariş %s - %s", number, marketLabel)
|
actor := strings.TrimSpace(claims.Username)
|
||||||
bodyHTML := fmt.Sprintf(
|
if actor == "" {
|
||||||
`<p>Sipariş kaydı oluşturuldu/güncellendi.</p><p><b>Sipariş No:</b> %s<br/><b>Cari:</b> %s<br/><b>Piyasa:</b> %s</p><p>PDF ektedir.</p>`,
|
actor = strings.TrimSpace(claims.V3Username)
|
||||||
htmlEsc(number),
|
}
|
||||||
htmlEsc(currAccCode),
|
if actor == "" {
|
||||||
htmlEsc(marketLabel),
|
actor = "Bilinmeyen Kullanici"
|
||||||
|
}
|
||||||
|
|
||||||
|
op := strings.ToLower(strings.TrimSpace(payload.Operation))
|
||||||
|
isUpdate := op == "update"
|
||||||
|
|
||||||
|
subjectAction := "SİPARİŞ KAYDI OLUŞTURULDU"
|
||||||
|
if isUpdate {
|
||||||
|
subjectAction = "SİPARİŞ GÜNCELLENDİ."
|
||||||
|
}
|
||||||
|
subject := fmt.Sprintf("%s kullanıcısı tarafından %s %s", actor, number, subjectAction)
|
||||||
|
|
||||||
|
cariDetail := ""
|
||||||
|
customerRep := ""
|
||||||
|
if header != nil {
|
||||||
|
cariDetail = strings.TrimSpace(header.CurrAccName)
|
||||||
|
customerRep = strings.TrimSpace(header.CustomerRep)
|
||||||
|
}
|
||||||
|
|
||||||
|
body := make([]string, 0, 12)
|
||||||
|
body = append(body,
|
||||||
|
`<p>`,
|
||||||
|
fmt.Sprintf(`<b>Cari Kodu:</b> %s<br/>`, htmlEsc(currAccCode)),
|
||||||
|
fmt.Sprintf(`<b>Cari Detay:</b> %s<br/>`, htmlEsc(cariDetail)),
|
||||||
|
fmt.Sprintf(`<b>Müşteri Temsilcisi:</b> %s<br/>`, htmlEsc(customerRep)),
|
||||||
|
fmt.Sprintf(`<b>Piyasa:</b> %s`, htmlEsc(marketLabel)),
|
||||||
|
`</p>`,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if isUpdate {
|
||||||
|
body = append(body,
|
||||||
|
renderItemListHTML("Silinen Ürün Kodları", payload.DeletedItems),
|
||||||
|
renderItemListHTML("Güncellenen Ürün Kodları", payload.UpdatedItems),
|
||||||
|
renderItemListHTML("Eklenen Ürün Kodları", payload.AddedItems),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
body = append(body, `<p><i>Bu sipariş BaggiSS App Uygulamasından oluşturulmuştur.</i></p>`)
|
||||||
|
body = append(body, `<p>PDF ektedir.</p>`)
|
||||||
|
bodyHTML := strings.Join(body, "\n")
|
||||||
|
|
||||||
fileNo := sanitizeFileName(number)
|
fileNo := sanitizeFileName(number)
|
||||||
if fileNo == "" {
|
if fileNo == "" {
|
||||||
fileNo = orderID
|
fileNo = orderID
|
||||||
@@ -256,3 +304,31 @@ func htmlEsc(s string) string {
|
|||||||
)
|
)
|
||||||
return r.Replace(s)
|
return r.Replace(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func renderItemListHTML(title string, items []string) string {
|
||||||
|
clean := make([]string, 0, len(items))
|
||||||
|
seen := make(map[string]struct{}, len(items))
|
||||||
|
for _, raw := range items {
|
||||||
|
v := strings.TrimSpace(raw)
|
||||||
|
if v == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := seen[v]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[v] = struct{}{}
|
||||||
|
clean = append(clean, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(clean) == 0 {
|
||||||
|
return fmt.Sprintf(`<p><b>%s:</b> Yok</p>`, htmlEsc(title))
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]string, 0, len(clean)+3)
|
||||||
|
b = append(b, fmt.Sprintf(`<p><b>%s:</b><br/>`, htmlEsc(title)))
|
||||||
|
for _, item := range clean {
|
||||||
|
b = append(b, "- "+htmlEsc(item)+"<br/>")
|
||||||
|
}
|
||||||
|
b = append(b, `</p>`)
|
||||||
|
return strings.Join(b, "\n")
|
||||||
|
}
|
||||||
|
|||||||
@@ -400,7 +400,68 @@ export const useOrderEntryStore = defineStore('orderentry', {
|
|||||||
}
|
}
|
||||||
,
|
,
|
||||||
|
|
||||||
async sendOrderToMarketMails(orderId) {
|
buildMailLineLabel(line) {
|
||||||
|
if (!line || typeof line !== 'object') return ''
|
||||||
|
|
||||||
|
const item = String(line.ItemCode || '').trim()
|
||||||
|
const color1 = String(line.ColorCode || '').trim()
|
||||||
|
const color2 = String(line.ItemDim2Code || '').trim()
|
||||||
|
const desc = String(line.LineDescription || '').trim()
|
||||||
|
|
||||||
|
if (!item) return ''
|
||||||
|
|
||||||
|
const colorPart = color2 ? `${color1}-${color2}` : color1
|
||||||
|
return [item, colorPart, desc].filter(Boolean).join(' ')
|
||||||
|
}
|
||||||
|
,
|
||||||
|
|
||||||
|
buildOrderMailPayload(lines = [], isNew = false) {
|
||||||
|
const uniq = (arr) => [...new Set((arr || []).map(v => String(v || '').trim()).filter(Boolean))]
|
||||||
|
|
||||||
|
const normalized = Array.isArray(lines) ? lines : []
|
||||||
|
const mapLabel = (ln) => this.buildMailLineLabel(ln)
|
||||||
|
|
||||||
|
if (isNew) {
|
||||||
|
return {
|
||||||
|
operation: 'create',
|
||||||
|
deletedItems: [],
|
||||||
|
updatedItems: [],
|
||||||
|
addedItems: uniq(
|
||||||
|
normalized
|
||||||
|
.filter(ln => !ln?._deleteSignal)
|
||||||
|
.map(mapLabel)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deletedItems = uniq(
|
||||||
|
normalized
|
||||||
|
.filter(ln => ln?._deleteSignal === true)
|
||||||
|
.map(mapLabel)
|
||||||
|
)
|
||||||
|
|
||||||
|
const updatedItems = uniq(
|
||||||
|
normalized
|
||||||
|
.filter(ln => !ln?._deleteSignal && !!ln?.OrderLineID && ln?._dirty === true)
|
||||||
|
.map(mapLabel)
|
||||||
|
)
|
||||||
|
|
||||||
|
const addedItems = uniq(
|
||||||
|
normalized
|
||||||
|
.filter(ln => !ln?._deleteSignal && !ln?.OrderLineID)
|
||||||
|
.map(mapLabel)
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
operation: 'update',
|
||||||
|
deletedItems,
|
||||||
|
updatedItems,
|
||||||
|
addedItems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,
|
||||||
|
|
||||||
|
async sendOrderToMarketMails(orderId, payload = {}) {
|
||||||
const id = String(orderId || this.header?.OrderHeaderID || '').trim()
|
const id = String(orderId || this.header?.OrderHeaderID || '').trim()
|
||||||
if (!id) {
|
if (!id) {
|
||||||
throw new Error('Sipariş ID bulunamadı')
|
throw new Error('Sipariş ID bulunamadı')
|
||||||
@@ -408,7 +469,11 @@ export const useOrderEntryStore = defineStore('orderentry', {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await api.post('/order/send-market-mail', {
|
const res = await api.post('/order/send-market-mail', {
|
||||||
orderHeaderID: id
|
orderHeaderID: id,
|
||||||
|
operation: payload?.operation || 'create',
|
||||||
|
deletedItems: Array.isArray(payload?.deletedItems) ? payload.deletedItems : [],
|
||||||
|
updatedItems: Array.isArray(payload?.updatedItems) ? payload.updatedItems : [],
|
||||||
|
addedItems: Array.isArray(payload?.addedItems) ? payload.addedItems : []
|
||||||
})
|
})
|
||||||
return res?.data || {}
|
return res?.data || {}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -2867,7 +2932,8 @@ export const useOrderEntryStore = defineStore('orderentry', {
|
|||||||
|
|
||||||
// 📧 Piyasa eşleşen alıcılara sipariş PDF gönderimi (kayıt başarılı olduktan sonra)
|
// 📧 Piyasa eşleşen alıcılara sipariş PDF gönderimi (kayıt başarılı olduktan sonra)
|
||||||
try {
|
try {
|
||||||
const mailRes = await this.sendOrderToMarketMails(serverOrderId)
|
const mailPayload = this.buildOrderMailPayload(lines, isNew)
|
||||||
|
const mailRes = await this.sendOrderToMarketMails(serverOrderId, mailPayload)
|
||||||
const sentCount = Number(mailRes?.sentCount || 0)
|
const sentCount = Number(mailRes?.sentCount || 0)
|
||||||
$q.notify({
|
$q.notify({
|
||||||
type: 'positive',
|
type: 'positive',
|
||||||
|
|||||||
Reference in New Issue
Block a user