Skip to content

Commit

Permalink
fix: right splitting of seller quotes
Browse files Browse the repository at this point in the history
  • Loading branch information
tiago-freire committed Dec 14, 2024
1 parent 5c5771f commit 70d1c4d
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 65 deletions.
7 changes: 3 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add new input quotesManagedBy on appSettings to handle splitting quotes
- Add new quote configuration to handle split quote by seller
- Verify if seller accept manage quotes
- Notify seller with quote payload if it accepts to manage quotes
- Add field quotesManagedBy on appSettings to handle splitting quotes
- Process splitting quote by seller if it accepts to manage quotes
- Notify seller with quote reference data as payload

## [2.6.4] - 2024-10-31

Expand Down
34 changes: 20 additions & 14 deletions node/clients/SellerQuotesClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ interface VerifyQuoteSettingsResponse {
receiveQuotes: boolean
}

interface NotifySellerQuoteResponse {
status: string
interface SellerQuoteNotifyInput {
quoteId: string
marketplaceAccount: string
}

const routes = {
verifyQuoteSettings: '/verify-quote-settings',
notifyNewQuote: '/notify-new-quote',
verifyQuoteSettings: 'verify-quote-settings',
notifyNewQuote: 'notify-new-quote',
}

export default class SellerQuotesClient extends ExternalClient {
Expand All @@ -35,24 +36,29 @@ export default class SellerQuotesClient extends ExternalClient {
})
}

private getRoute(account: string, path: string) {
private getRoute(sellerAccount: string, path: string) {
const subdomain = this.context.production
? account
: `${this.context.workspace}--${account}`
? sellerAccount
: `${this.context.workspace}--${sellerAccount}`

return `http://${subdomain}.myvtex.com/_v/b2b-seller-quotes${path}`
return `http://${subdomain}.myvtex.com/b2b-seller-quotes/_v/0/${path}`
}

public async verifyQuoteSettings(account: string) {
public async verifyQuoteSettings(sellerAccount: string) {
return this.http.get<VerifyQuoteSettingsResponse>(
this.getRoute(account, routes.verifyQuoteSettings)
this.getRoute(sellerAccount, routes.verifyQuoteSettings)
)
}

public async notifyNewQuote(account: string, quote: Quote) {
return this.http.postRaw<NotifySellerQuoteResponse>(
this.getRoute(account, routes.notifyNewQuote),
quote
public async notifyNewQuote(sellerAccount: string, quoteId: string) {
const payload: SellerQuoteNotifyInput = {
quoteId,
marketplaceAccount: this.context.account,
}

return this.http.postRaw(
this.getRoute(sellerAccount, routes.notifyNewQuote),
payload
)
}
}
107 changes: 60 additions & 47 deletions node/resolvers/mutations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
checkQuoteStatus,
checkSession,
} from '../utils/checkPermissions'
import { createQuoteObject } from '../utils/quotes'
import { createQuoteObject, processSellerItems } from '../utils/quotes'

export const Mutation = {
clearCart: async (_: any, params: any, ctx: Context) => {
Expand Down Expand Up @@ -81,55 +81,68 @@ export const Mutation = {
throw new GraphQLError('operation-not-permitted')
}

const parentQuote = createQuoteObject({
sessionData,
storefrontPermissions,
segmentData,
settings,
items,
referenceName,
subtotal,
note,
sendToSalesRep,
})

try {
const { DocumentId: parentQuoteId } = await masterdata.createDocument({
dataEntity: QUOTE_DATA_ENTITY,
fields: parentQuote,
schema: SCHEMA_VERSION,
})
const quoteBySeller: Record<string, SellerQuoteInput> = {}

if (settings?.adminSetup.quotesManagedBy === 'SELLER') {
const quoteBySeller: Record<string, SellerQuoteInput> = {}

items.forEach(({ seller, sellingPrice, ...itemData }) => {
if (!quoteBySeller[seller]) {
quoteBySeller[seller] = {
items: [],
referenceName,
note,
sendToSalesRep,
subtotal: 0,
}
}
const sellerItems = items.filter(
({ seller }) => seller && seller !== '1'
)

quoteBySeller[seller].items.push({
seller,
sellingPrice,
...itemData,
})
quoteBySeller[seller].subtotal += sellingPrice * itemData.quantity
await processSellerItems({
ctx,
quoteBySeller,
referenceName,
note,
sendToSalesRep,
items: sellerItems,
})
}

const documentIds = await Promise.all(
Object.entries(quoteBySeller).map(async ([seller, sellerQuote]) => {
const verifyResponse = await ctx.clients.sellerQuotes.verifyQuoteSettings(
seller
)
const hasSellerQuotes = Object.keys(quoteBySeller).length

const parentQuoteItems = hasSellerQuotes
? items.filter(
(item) =>
!Object.values(quoteBySeller).some((quote) =>
quote.items.some((quoteItem) => quoteItem.id === item.id)
)
)
: items

// We believe that parent quote should contain the overall subtotal.
// If for some reason it is necessary to subtract the subtotal from
// sellers quotes, we can use the adjustedSubtotal below, assigning
// it to subtotal in createQuoteObject (subtotal: adjustedSubtotal).
//
// const adjustedSubtotal = hasSellerQuotes
// ? Object.values(quoteBySeller).reduce(
// (acc, quote) => acc - quote.subtotal,
// subtotal
// )
// : subtotal

const parentQuote = createQuoteObject({
sessionData,
storefrontPermissions,
segmentData,
settings,
items: parentQuoteItems,
referenceName,
subtotal,
note,
sendToSalesRep,
})

if (!verifyResponse.receiveQuotes) return null
const { DocumentId: parentQuoteId } = await masterdata.createDocument({
dataEntity: QUOTE_DATA_ENTITY,
fields: parentQuote,
schema: SCHEMA_VERSION,
})

if (hasSellerQuotes) {
const sellerQuoteIds = await Promise.all(
Object.entries(quoteBySeller).map(async ([seller, sellerQuote]) => {
const sellerQuoteObject = createQuoteObject({
sessionData,
storefrontPermissions,
Expand All @@ -151,16 +164,16 @@ export const Mutation = {
schema: SCHEMA_VERSION,
})

await ctx.clients.sellerQuotes.notifyNewQuote(seller, {
id: data.DocumentId,
...sellerQuoteObject,
})
await ctx.clients.sellerQuotes.notifyNewQuote(
seller,
data.DocumentId
)

return data.DocumentId
})
)

if (documentIds.filter(Boolean).length) {
if (sellerQuoteIds.length) {
await masterdata.updatePartialDocument({
dataEntity: QUOTE_DATA_ENTITY,
fields: { hasChildren: true },
Expand Down
59 changes: 59 additions & 0 deletions node/resolvers/utils/quotes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,62 @@
export async function processSellerItems({
ctx,
quoteBySeller,
referenceName,
note,
sendToSalesRep,
items,
index = 0,
}: {
ctx: Context
quoteBySeller: Record<string, SellerQuoteInput>
referenceName: string
note: string
sendToSalesRep: boolean
items: QuoteItem[]
index?: number
}): Promise<void> {
if (index >= items.length) return

const item = items[index]
const { seller } = item

const next = async () =>
processSellerItems({
ctx,
quoteBySeller,
referenceName,
note,
sendToSalesRep,
items,
index: index + 1,
})

const verifyResponse = await ctx.clients.sellerQuotes
.verifyQuoteSettings(seller)
.catch(() => null)

if (!verifyResponse?.receiveQuotes) {
await next()

return
}

if (!quoteBySeller[seller]) {
quoteBySeller[seller] = {
items: [],
referenceName,
note,
sendToSalesRep,
subtotal: 0,
}
}

quoteBySeller[seller].items.push(item)
quoteBySeller[seller].subtotal += item.sellingPrice * item.quantity

await next()
}

export const createQuoteObject = ({
sessionData,
storefrontPermissions,
Expand Down

0 comments on commit 70d1c4d

Please sign in to comment.