Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export returns module #198

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Added

- A new feature called Export module; allowing to report all records into a single file.

## [3.5.5] - 2022-11-11
### Fixed
- Allow creation of a return for orders placed with a ` PICKUP_POINT` as customer address.
Expand Down
17 changes: 15 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
Return app v3 is still in BETA. v2 will no longer be supported so please do not install it.
Docs are WIP.

- Table of contents
- [Features](#features)
- [API](#api)
- [Customization](#customization)
- [Known issues](#known-issues)
- [Development](#development)

## Description

The **Return App** gives merchants the option to allow customers to request a return for their items and it gives them the ability to manage the Return Request Process on their store.
Expand All @@ -15,7 +22,7 @@ Here a customer will be able to visualize the history, status and details of the


### Admin: Return Request List
In this section of the merchant's admin, merchants are capable of visualizing and managing all the return requests created by their customers.
In this section of the merchant's admin, merchants are capable of visualizing and managing all the return requests created by their customers, while also being able to export all or some records to a single file.


### Admin: Return Settings
Expand Down Expand Up @@ -303,11 +310,17 @@ In order to apply CSS customizations in this and other blocks, follow the instru
|'termsAndConditionsLink'|
|'userCommentDetailsContainer'|

## Knowing issues
## Known issues
- When a store has a process to create return invoices ([invoice type input](https://developers.vtex.com/vtex-rest-api/reference/invoicenotification)) outside the return app, the app will consider those items and they will not be able to be returned via the app. However when an item is already committed in a return request and an invoice is created considering that item with a invoice number different than the return request id, there will be more processed items to return then invoices items - It can be seen using the query `orderToReturnSummary` on GraphQL.

- When installing the app in a workspace - or creating a new one - the app will not behavior as expected. This is due to the masterdata builder not creating a schema for that workspace automatically. To fix that, one can just link the app in the workspace using the toolbelt. Doing so, there will be a new masterdata schema related to that workspace and the app should work fine.

## Development

### Export feature (Report)

This app leverages the Report API to export all return documents into a single file. For this to work, we maintain a matrix transformation MAP inside **/node/report**. If any key or value of the object is changed, next time any account that opens the module will have their map created/updated. The ID is the identifier we use to compare them, there's no need of changing it every time we modify the object.

---
Documentation for v2 [here](https://github.com/vtex-apps/return-app/tree/v2).

Expand Down
4 changes: 4 additions & 0 deletions graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type Query {
@withUserProfile
@cacheControl(scope: PRIVATE, maxAge: SHORT)
nearestPickupPoints(lat: String!, long: String!): NearPickupPointQueryResponse
exportStatus: ExportReportData @cacheControl(scope: PRIVATE, maxAge: ZERO)
}

type Mutation {
Expand All @@ -42,4 +43,7 @@ type Mutation {
comment: ReturnRequestCommentInput
refundData: RefundDataInput
): ReturnRequestResponse @withUserProfile
exportReturnRequests(
exportData: ExportReturnRequestsInput!
): ExportReportData @withUserProfile
}
57 changes: 57 additions & 0 deletions graphql/types/ExportReturnRequests.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
type ExportReportData {
id: String
inProgress: Boolean
percentageProcessed: Float
requestedBy: String
completedDate: String
"""
Masterdata _WHERE filter
"""
selectedFilters: String
downloadLink: String
"""
Download link expires 6 hours after completed
"""
staleLink: Boolean
lastErrorMessage: String
}

input ExportReturnRequestsInput {
fileFormat: ExportFormatInput!
"""
Masterdata _WHERE filter
"""
documentsFilter: String
"""
If not provided, the file will only be accesible via export status download link
"""
deliveryConfiguration: DeliveryConfigurationData
}

enum ExportFormatInput {
XLSX
"""
UNTESTED
"""
CSV
"""
UNTESTED
"""
JSON
}

input DeliveryConfigurationData {
type: DeliveryTypeInput!
value: String!
}

enum DeliveryTypeInput {
"""
Send file to endpoint
"""
ENDPOINT
"""
Send file to email
"""
EMAIL
}
23 changes: 22 additions & 1 deletion messages/context.json
Original file line number Diff line number Diff line change
Expand Up @@ -329,5 +329,26 @@
"return-app.return-request-details.cancellation.modal.adminAllow": "Text message for allowing a cancellation for admins",
"return-app.return-request-details.cancellation.modal.adminRefuse": "Text message for refusing a cancellation for admins",
"return-app.return-request-details.cancellation.modal.storeAllow": "Text message for allowing a cancellation for store users",
"return-app.return-request-details.cancellation.modal.storeRefuse": "Text message for refusing a cancellation for store users"
"return-app.return-request-details.cancellation.modal.storeRefuse": "Text message for refusing a cancellation for store users",
"admin/return-app.export-module.modal-open": "Open export modal CTA",
"admin/return-app.export-module.modal-title": "Export modal title",
"admin/return-app.export-module.modal-close": "Export modal close CTA",
"admin/return-app.export-module.content.first-paragraph": "Export explanation content, first paragraph",
"admin/return-app.export-module.content.second-paragraph": "Export explanation content, second paragraph",
"admin/return-app.export-module.content.warning-paragraph": "Export explanation content, warning paragraph",
"admin/return-app.export-module.content.format-disclaimer": "Export file format disclaimer",
"admin/return-app.export-module.content.skip-disclaimer": "Export skip record disclaimer",
"admin/return-app.export-module.report.status-title": "Report status section title",
"admin/return-app.export-module.report.download-cta": "Export file download CTA",
"admin/return-app.export-module.report.status-requestedBy": "Export status, requested-by field",
"admin/return-app.export-module.report.status-completedDate": "Export status, completed-date field",
"admin/return-app.export-module.report.status-filterRange": "Export status, filter-range field",
"admin/return-app.export-module.report.status-tag.error": "Export status error tag",
"admin/return-app.export-module.report.status-tag.inProgress": "Export status in progress tag",
"admin/return-app.export-module.report.status-tag.ready": "Export status ready tag",
"admin/return-app.export-module.report.form-title": "Report form section title",
"admin/return-app.export-module.report.form-allRequests-toggle": "Export form toggle label for filters",
"admin/return-app.export-module.report.form-email-toggle": "Export form toggle label for email",
"admin/return-app.export-module.report.form-email-placeholder": "Export form input placeholder for email",
"admin/return-app.export-module.report.form-cta": "Export form CTA"
}
23 changes: 22 additions & 1 deletion messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -329,5 +329,26 @@
"return-app.return-request-details.cancellation.modal.adminAllow": "<p>Attention: This request's status will be set to CANCELLED.</p><p>This will notify the user via email and allow them to create a new return request with the cancelled request's items.</p><p>If that is not your intention, set the request as DENIED.</p>",
"return-app.return-request-details.cancellation.modal.adminRefuse": "<p>Sorry, it's not possible to cancel this request due to its current status.</p>",
"return-app.return-request-details.cancellation.modal.storeAllow": "<p>Cancelling this request will allow the current items to be used in a new return request.</p><p>This action is irreversible.</p>",
"return-app.return-request-details.cancellation.modal.storeRefuse": "<p>Sorry, you need to contact the support team to cancel this request due to its current status.</p>"
"return-app.return-request-details.cancellation.modal.storeRefuse": "<p>Sorry, you need to contact the support team to cancel this request due to its current status.</p>",
"admin/return-app.export-module.modal-open": "EXPORT RETURNS",
"admin/return-app.export-module.modal-title": "Export module",
"admin/return-app.export-module.modal-close": "CLOSE",
"admin/return-app.export-module.content.first-paragraph": "The Export module is the system responsible for merging all return requests into a single file called <b>report</b>, this can be then sent to an email or downloaded directly from this module",
"admin/return-app.export-module.content.second-paragraph": "Keep in mind that download links are not permanent, they expire after <b>6 hours</b> following their availability",
"admin/return-app.export-module.content.warning-paragraph": "As the export process runs in the backround, if you only chose to generate a download link, you can close this page and check back later; if not, you'll be alerted via email",
"admin/return-app.export-module.content.format-disclaimer": "Supported formats:",
"admin/return-app.export-module.content.skip-disclaimer": "Documents containing errors will be skipped",
"admin/return-app.export-module.report.status-title": "Last report",
"admin/return-app.export-module.report.download-cta": "Download link",
"admin/return-app.export-module.report.status-requestedBy": "Requested by:",
"admin/return-app.export-module.report.status-completedDate": "Completed date:",
"admin/return-app.export-module.report.status-filterRange": "Filter range:",
"admin/return-app.export-module.report.status-tag.error": "Error, please try again",
"admin/return-app.export-module.report.status-tag.inProgress": "In Progress",
"admin/return-app.export-module.report.status-tag.ready": "Ready",
"admin/return-app.export-module.report.form-title": "New report",
"admin/return-app.export-module.report.form-allRequests-toggle": "All requests",
"admin/return-app.export-module.report.form-email-toggle": "Send file to email",
"admin/return-app.export-module.report.form-email-placeholder": "Recipient email",
"admin/return-app.export-module.report.form-cta": "GENERATE"
}
16 changes: 16 additions & 0 deletions node/clients/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IOClients, Sphinx } from '@vtex/api'
import { vbaseFor, masterDataFor } from '@vtex/clients'
import { ReturnAppSettings, ReturnRequest } from 'vtex.return-app'
import type { ExportReportData } from 'vtex.return-app'

import { Catalog } from './catalog'
import { OMSCustom as OMS } from './oms'
Expand All @@ -9,8 +10,15 @@ import { MailClient } from './mail'
import Checkout from './checkout'
import { VtexId } from './vtexId'
import { CatalogGQL } from './catalogGQL'
import { ReturnRequestReport } from './report'

type ExportReportDataVBase = Pick<
ExportReportData,
'id' | 'selectedFilters' | 'requestedBy'
>

const ReturnAppSettings = vbaseFor<string, ReturnAppSettings>('appSettings')
const ExportReport = vbaseFor<string, ExportReportDataVBase>('exportReport')
const ReturnRequest = masterDataFor<ReturnRequest>('returnRequest')

export class Clients extends IOClients {
Expand All @@ -22,6 +30,10 @@ export class Clients extends IOClients {
return this.getOrSet('appSettings', ReturnAppSettings)
}

public get exportReport() {
return this.getOrSet('exportReport', ExportReport)
}

public get catalog() {
return this.getOrSet('catalog', Catalog)
}
Expand All @@ -34,6 +46,10 @@ export class Clients extends IOClients {
return this.getOrSet('returnRequest', ReturnRequest)
}

public get report() {
return this.getOrSet('report', ReturnRequestReport)
}

public get giftCard() {
return this.getOrSet('giftCard', GiftCard)
}
Expand Down
42 changes: 42 additions & 0 deletions node/clients/report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { InstanceOptions, IOContext } from '@vtex/api'
import { JanusClient } from '@vtex/api'

const baseURL = '/api/report'

const routes = {
masterdata: `${baseURL}/masterdata`,
inProgress: `${baseURL}/inprogress`,
report: (id: string) => `${baseURL}/${id}`,
map: (id: string) => `${baseURL}/map/${id}`,
}

/**
* API used to create a complete report of a masterdata entity
*/
export class ReturnRequestReport extends JanusClient {
constructor(context: IOContext, options?: InstanceOptions) {
super(context, {
...options,
headers: {
VtexIdclientAutCookie: context.authToken,
...(options?.headers ?? {}),
},
})
}

public getMap = (mapId: string) => this.http.get(routes.map(mapId))

public createOrUpdateMap = (map: ReportMap) =>
this.http.put<ReportMap>(routes.map(map.id), map)

public deleteMap = (mapId: string) => this.http.delete(routes.map(mapId))

public inProgressReports = () =>
this.http.get<MasterdataReportsResponse[]>(routes.inProgress)

public getReport = (reportId: string) =>
this.http.get<Report>(routes.report(reportId))

public generateReport = (reportConfig: MasterdataReportsConfig) =>
this.http.post<MasterdataReportsResponse>(routes.masterdata, reportConfig)
}
Loading