Add store-item Excel export/import for bulk price and stock updates.
Dashboard can download grouped product variants and re-upload to update price and stock. Also expose Content-Disposition for downloads and keep related product/customer API docs in sync. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
4a5780e74d
commit
7277817b6e
@@ -18,6 +18,8 @@ type CustomerListRow = {
|
||||
cellNumber: string;
|
||||
firstName: string | null;
|
||||
lastName: string | null;
|
||||
firstNameEn: string | null;
|
||||
lastNameEn: string | null;
|
||||
email: string | null;
|
||||
createdAt: Date;
|
||||
isEnabled: boolean;
|
||||
@@ -63,7 +65,10 @@ export class CustomersService {
|
||||
AND (
|
||||
u.first_name ILIKE ${nameLike}
|
||||
OR u.last_name ILIKE ${nameLike}
|
||||
OR u.first_name_en ILIKE ${nameLike}
|
||||
OR u.last_name_en ILIKE ${nameLike}
|
||||
OR (COALESCE(u.first_name, '') || ' ' || COALESCE(u.last_name, '')) ILIKE ${nameLike}
|
||||
OR (COALESCE(u.first_name_en, '') || ' ' || COALESCE(u.last_name_en, '')) ILIKE ${nameLike}
|
||||
)
|
||||
` : Prisma.empty}
|
||||
${cellLike ? Prisma.sql`AND u.cell_number ILIKE ${cellLike}` : Prisma.empty}
|
||||
@@ -76,6 +81,8 @@ export class CustomersService {
|
||||
u.cell_number AS "cellNumber",
|
||||
u.first_name AS "firstName",
|
||||
u.last_name AS "lastName",
|
||||
u.first_name_en AS "firstNameEn",
|
||||
u.last_name_en AS "lastNameEn",
|
||||
u.email AS "email",
|
||||
COALESCE(bc.created_at, bu.created_at) AS "createdAt",
|
||||
COALESCE(bc.is_enabled, TRUE) AS "isEnabled",
|
||||
@@ -109,6 +116,8 @@ export class CustomersService {
|
||||
cellNumber: user.cellNumber,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
firstNameEn: user.firstNameEn,
|
||||
lastNameEn: user.lastNameEn,
|
||||
email: user.email,
|
||||
label: this.formatLabel(user),
|
||||
createdAt: user.createdAt.toISOString(),
|
||||
@@ -335,6 +344,8 @@ export class CustomersService {
|
||||
cellNumber: user.cellNumber,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
firstNameEn: user.firstNameEn,
|
||||
lastNameEn: user.lastNameEn,
|
||||
email: user.email,
|
||||
label: this.formatLabel(user),
|
||||
createdAt: membership.link.createdAt.toISOString(),
|
||||
@@ -375,6 +386,8 @@ export class CustomersService {
|
||||
const hasProfileUpdate =
|
||||
dto.firstName !== undefined ||
|
||||
dto.lastName !== undefined ||
|
||||
dto.firstNameEn !== undefined ||
|
||||
dto.lastNameEn !== undefined ||
|
||||
dto.email !== undefined ||
|
||||
dto.cellNumber !== undefined;
|
||||
|
||||
@@ -395,6 +408,10 @@ export class CustomersService {
|
||||
data: {
|
||||
firstName: dto.firstName?.trim(),
|
||||
lastName: dto.lastName?.trim(),
|
||||
firstNameEn:
|
||||
dto.firstNameEn !== undefined ? dto.firstNameEn.trim() || null : undefined,
|
||||
lastNameEn:
|
||||
dto.lastNameEn !== undefined ? dto.lastNameEn.trim() || null : undefined,
|
||||
email: dto.email !== undefined ? dto.email.trim() || null : undefined,
|
||||
cellNumber: dto.cellNumber?.trim(),
|
||||
},
|
||||
@@ -416,6 +433,8 @@ export class CustomersService {
|
||||
cellNumber: user.cellNumber,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
firstNameEn: user.firstNameEn,
|
||||
lastNameEn: user.lastNameEn,
|
||||
email: user.email,
|
||||
label: this.formatLabel(user),
|
||||
isEnabled: refreshed.isEnabled,
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import { IsBoolean, IsOptional, IsString, MinLength } from 'class-validator';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsOptional,
|
||||
IsString,
|
||||
MaxLength,
|
||||
MinLength,
|
||||
ValidateIf,
|
||||
} from 'class-validator';
|
||||
|
||||
export class UpdateCustomerDto {
|
||||
@IsOptional()
|
||||
@@ -8,13 +15,29 @@ export class UpdateCustomerDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(100)
|
||||
firstName?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(100)
|
||||
lastName?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ValidateIf((_, value) => typeof value === 'string' && value.trim().length > 0)
|
||||
@MinLength(2)
|
||||
@MaxLength(100)
|
||||
firstNameEn?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ValidateIf((_, value) => typeof value === 'string' && value.trim().length > 0)
|
||||
@MinLength(2)
|
||||
@MaxLength(100)
|
||||
lastNameEn?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
email?: string;
|
||||
|
||||
Reference in New Issue
Block a user