chore(price-types): drop IsDefault flag + rename IsRetail label + uniqueness
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 46s
CI / Web (React + Vite) (push) Successful in 34s
Docker API / Build + push API (push) Successful in 40s
Docker Web / Build + push Web (push) Successful in 27s
Docker API / Deploy API on stage (push) Successful in 17s
Docker Web / Deploy Web on stage (push) Successful in 11s
Some checks are pending
CI / POS (WPF, Windows) (push) Waiting to run
CI / Backend (.NET 8) (push) Successful in 46s
CI / Web (React + Vite) (push) Successful in 34s
Docker API / Build + push API (push) Successful in 40s
Docker Web / Build + push Web (push) Successful in 27s
Docker API / Deploy API on stage (push) Successful in 17s
Docker Web / Deploy Web on stage (push) Successful in 11s
PriceType: убран флаг IsDefault — он семантически дублировал IsSystem
(защищённая запись «по умолчанию»). Остаются IsSystem / IsRequired /
IsRetail.
- Domain.Catalog.PriceType: удалено поле IsDefault.
- Миграция Phase3b_DropPriceTypeIsDefault: DROP COLUMN.
- DTO/Input (PriceTypeDto, PriceTypeInput) — без IsDefault.
- PriceTypesController:
• убрана логика uniqueness IsDefault на Create/Update,
• IsRetail теперь enforce'ит уникальность: при установке IsRetail=true
у других записей сбрасывается,
• при удалении единственной IsRetail записи (если она не системная)
IsRetail автоматически переезжает на IsSystem-запись — у организации
всегда остаётся один POS-кандидат.
- ProductsController.RecalcRetail и SuppliesController.SetDefaultRetail —
поиск дефолтной розничной идёт по IsSystem → IsRetail → SortOrder → Name
(ранее ThenByDescending(IsDefault) — выпилено).
- DevDataSeeder: поле IsDefault убрано.
- web types.ts: убрано isDefault из PriceType.
- PriceTypesPage:
• убран чекбокс «По умолчанию»,
• лейбл «Розничная (используется на кассе)» → «Используется на кассе»,
• Form/blankForm/onRowClick без isDefault.
- ProductsPage / ProductEditPage: фоллбэк дефолтной цены теперь
IsSystem → IsRetail → первая.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5614fb9422
commit
bcc6976bd0
|
|
@ -37,7 +37,7 @@ public async Task<ActionResult<PagedResult<PriceTypeDto>>> List([FromQuery] Page
|
||||||
};
|
};
|
||||||
var items = await q
|
var items = await q
|
||||||
.Skip(req.Skip).Take(req.Take)
|
.Skip(req.Skip).Take(req.Take)
|
||||||
.Select(p => new PriceTypeDto(p.Id, p.Name, p.IsRequired, p.IsSystem, p.IsDefault, p.IsRetail, p.SortOrder))
|
.Select(p => new PriceTypeDto(p.Id, p.Name, p.IsRequired, p.IsSystem, p.IsRetail, p.SortOrder))
|
||||||
.ToListAsync(ct);
|
.ToListAsync(ct);
|
||||||
return new PagedResult<PriceTypeDto> { Items = items, Total = total, Page = req.Page, PageSize = req.Take };
|
return new PagedResult<PriceTypeDto> { Items = items, Total = total, Page = req.Page, PageSize = req.Take };
|
||||||
}
|
}
|
||||||
|
|
@ -46,29 +46,30 @@ public async Task<ActionResult<PagedResult<PriceTypeDto>>> List([FromQuery] Page
|
||||||
public async Task<ActionResult<PriceTypeDto>> Get(Guid id, CancellationToken ct)
|
public async Task<ActionResult<PriceTypeDto>> Get(Guid id, CancellationToken ct)
|
||||||
{
|
{
|
||||||
var p = await _db.PriceTypes.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, ct);
|
var p = await _db.PriceTypes.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, ct);
|
||||||
return p is null ? NotFound() : new PriceTypeDto(p.Id, p.Name, p.IsRequired, p.IsSystem, p.IsDefault, p.IsRetail, p.SortOrder);
|
return p is null ? NotFound() : new PriceTypeDto(p.Id, p.Name, p.IsRequired, p.IsSystem, p.IsRetail, p.SortOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost, Authorize(Roles = "Admin,Manager")]
|
[HttpPost, Authorize(Roles = "Admin,Manager")]
|
||||||
public async Task<ActionResult<PriceTypeDto>> Create([FromBody] PriceTypeInput input, CancellationToken ct)
|
public async Task<ActionResult<PriceTypeDto>> Create([FromBody] PriceTypeInput input, CancellationToken ct)
|
||||||
{
|
{
|
||||||
if (input.IsDefault)
|
if (input.IsRetail)
|
||||||
{
|
{
|
||||||
await _db.PriceTypes.Where(p => p.IsDefault).ExecuteUpdateAsync(s => s.SetProperty(p => p.IsDefault, false), ct);
|
// Уникальность IsRetail: не более одной записи в организации.
|
||||||
|
await _db.PriceTypes.Where(p => p.IsRetail)
|
||||||
|
.ExecuteUpdateAsync(s => s.SetProperty(p => p.IsRetail, false), ct);
|
||||||
}
|
}
|
||||||
var e = new PriceType
|
var e = new PriceType
|
||||||
{
|
{
|
||||||
Name = input.Name,
|
Name = input.Name,
|
||||||
IsRequired = input.IsRequired,
|
IsRequired = input.IsRequired,
|
||||||
IsSystem = false,
|
IsSystem = false,
|
||||||
IsDefault = input.IsDefault,
|
|
||||||
IsRetail = input.IsRetail,
|
IsRetail = input.IsRetail,
|
||||||
SortOrder = input.SortOrder,
|
SortOrder = input.SortOrder,
|
||||||
};
|
};
|
||||||
_db.PriceTypes.Add(e);
|
_db.PriceTypes.Add(e);
|
||||||
await _db.SaveChangesAsync(ct);
|
await _db.SaveChangesAsync(ct);
|
||||||
return CreatedAtAction(nameof(Get), new { id = e.Id },
|
return CreatedAtAction(nameof(Get), new { id = e.Id },
|
||||||
new PriceTypeDto(e.Id, e.Name, e.IsRequired, e.IsSystem, e.IsDefault, e.IsRetail, e.SortOrder));
|
new PriceTypeDto(e.Id, e.Name, e.IsRequired, e.IsSystem, e.IsRetail, e.SortOrder));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut("{id:guid}"), Authorize(Roles = "Admin,Manager")]
|
[HttpPut("{id:guid}"), Authorize(Roles = "Admin,Manager")]
|
||||||
|
|
@ -76,12 +77,13 @@ public async Task<IActionResult> Update(Guid id, [FromBody] PriceTypeInput input
|
||||||
{
|
{
|
||||||
var e = await _db.PriceTypes.FirstOrDefaultAsync(x => x.Id == id, ct);
|
var e = await _db.PriceTypes.FirstOrDefaultAsync(x => x.Id == id, ct);
|
||||||
if (e is null) return NotFound();
|
if (e is null) return NotFound();
|
||||||
if (input.IsDefault && !e.IsDefault)
|
if (input.IsRetail && !e.IsRetail)
|
||||||
{
|
{
|
||||||
await _db.PriceTypes.Where(p => p.IsDefault && p.Id != id).ExecuteUpdateAsync(s => s.SetProperty(p => p.IsDefault, false), ct);
|
// Снимаем IsRetail с прежней записи (если была) — гарантия уникальности.
|
||||||
|
await _db.PriceTypes.Where(p => p.IsRetail && p.Id != id)
|
||||||
|
.ExecuteUpdateAsync(s => s.SetProperty(p => p.IsRetail, false), ct);
|
||||||
}
|
}
|
||||||
e.Name = input.Name;
|
e.Name = input.Name;
|
||||||
e.IsDefault = input.IsDefault;
|
|
||||||
e.IsRetail = input.IsRetail;
|
e.IsRetail = input.IsRetail;
|
||||||
e.SortOrder = input.SortOrder;
|
e.SortOrder = input.SortOrder;
|
||||||
// У системной записи IsRequired всегда true и не меняется.
|
// У системной записи IsRequired всегда true и не меняется.
|
||||||
|
|
@ -96,8 +98,25 @@ public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
||||||
var e = await _db.PriceTypes.FirstOrDefaultAsync(x => x.Id == id, ct);
|
var e = await _db.PriceTypes.FirstOrDefaultAsync(x => x.Id == id, ct);
|
||||||
if (e is null) return NotFound();
|
if (e is null) return NotFound();
|
||||||
if (e.IsSystem) return BadRequest(new { error = "Системная запись не может быть удалена." });
|
if (e.IsSystem) return BadRequest(new { error = "Системная запись не может быть удалена." });
|
||||||
|
var wasRetail = e.IsRetail;
|
||||||
_db.PriceTypes.Remove(e);
|
_db.PriceTypes.Remove(e);
|
||||||
await _db.SaveChangesAsync(ct);
|
await _db.SaveChangesAsync(ct);
|
||||||
|
|
||||||
|
// Если удалённая запись была единственной IsRetail — фоллбэк на системную,
|
||||||
|
// чтобы у организации всегда оставался один IsRetail-кандидат для POS.
|
||||||
|
if (wasRetail)
|
||||||
|
{
|
||||||
|
var stillRetail = await _db.PriceTypes.AnyAsync(p => p.IsRetail, ct);
|
||||||
|
if (!stillRetail)
|
||||||
|
{
|
||||||
|
var sys = await _db.PriceTypes.FirstOrDefaultAsync(p => p.IsSystem, ct);
|
||||||
|
if (sys is not null && !sys.IsRetail)
|
||||||
|
{
|
||||||
|
sys.IsRetail = true;
|
||||||
|
await _db.SaveChangesAsync(ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -333,7 +333,6 @@ public async Task<IActionResult> RecalcRetail(Guid id, CancellationToken ct)
|
||||||
|
|
||||||
var defaultType = await _db.PriceTypes
|
var defaultType = await _db.PriceTypes
|
||||||
.OrderByDescending(pt => pt.IsSystem)
|
.OrderByDescending(pt => pt.IsSystem)
|
||||||
.ThenByDescending(pt => pt.IsDefault)
|
|
||||||
.ThenByDescending(pt => pt.IsRetail)
|
.ThenByDescending(pt => pt.IsRetail)
|
||||||
.ThenBy(pt => pt.SortOrder)
|
.ThenBy(pt => pt.SortOrder)
|
||||||
.ThenBy(pt => pt.Name)
|
.ThenBy(pt => pt.Name)
|
||||||
|
|
|
||||||
|
|
@ -296,13 +296,12 @@ public async Task<IActionResult> Post(Guid id, CancellationToken ct)
|
||||||
|
|
||||||
/// <summary>Записывает значение в дефолтный розничный PriceType. Если в списке
|
/// <summary>Записывает значение в дефолтный розничный PriceType. Если в списке
|
||||||
/// цен у товара такой записи нет — создаёт её. Дефолтным считается PriceType
|
/// цен у товара такой записи нет — создаёт её. Дефолтным считается PriceType
|
||||||
/// с IsDefault=true; если такого нет — первый IsRetail; иначе — первый
|
/// с IsSystem=true; если такого нет — первый IsRetail; иначе — первый
|
||||||
/// PriceType в списке. Currency берётся из приёмки (или из существующей записи).</summary>
|
/// PriceType в списке. Currency берётся из приёмки (или из существующей записи).</summary>
|
||||||
private void SetDefaultRetail(foodmarket.Domain.Catalog.Product p, decimal value, Guid fallbackCurrencyId)
|
private void SetDefaultRetail(foodmarket.Domain.Catalog.Product p, decimal value, Guid fallbackCurrencyId)
|
||||||
{
|
{
|
||||||
var defaultType = _db.PriceTypes
|
var defaultType = _db.PriceTypes
|
||||||
.OrderByDescending(pt => pt.IsSystem)
|
.OrderByDescending(pt => pt.IsSystem)
|
||||||
.ThenByDescending(pt => pt.IsDefault)
|
|
||||||
.ThenByDescending(pt => pt.IsRetail)
|
.ThenByDescending(pt => pt.IsRetail)
|
||||||
.ThenBy(pt => pt.SortOrder)
|
.ThenBy(pt => pt.SortOrder)
|
||||||
.ThenBy(pt => pt.Name)
|
.ThenBy(pt => pt.Name)
|
||||||
|
|
@ -391,7 +390,7 @@ orderby l.SortOrder
|
||||||
l.Quantity, l.UnitPrice, l.LineTotal, l.SortOrder,
|
l.Quantity, l.UnitPrice, l.LineTotal, l.SortOrder,
|
||||||
l.RetailPriceManuallyOverridden, l.RetailPriceOverride,
|
l.RetailPriceManuallyOverridden, l.RetailPriceOverride,
|
||||||
p.Prices
|
p.Prices
|
||||||
.OrderByDescending(pr => pr.PriceType!.IsDefault)
|
.OrderByDescending(pr => pr.PriceType!.IsSystem)
|
||||||
.ThenByDescending(pr => pr.PriceType!.IsRetail)
|
.ThenByDescending(pr => pr.PriceType!.IsRetail)
|
||||||
.ThenBy(pr => pr.PriceType!.SortOrder)
|
.ThenBy(pr => pr.PriceType!.SortOrder)
|
||||||
.ThenBy(pr => pr.PriceType!.Name)
|
.ThenBy(pr => pr.PriceType!.Name)
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ private static async Task SeedTenantReferencesAsync(AppDbContext db, Guid orgId,
|
||||||
if (!anyPriceType)
|
if (!anyPriceType)
|
||||||
{
|
{
|
||||||
db.PriceTypes.AddRange(
|
db.PriceTypes.AddRange(
|
||||||
new PriceType { OrganizationId = orgId, Name = "Розничная цена", IsSystem = true, IsRequired = true, IsDefault = true, IsRetail = true, SortOrder = 0 },
|
new PriceType { OrganizationId = orgId, Name = "Розничная цена", IsSystem = true, IsRequired = true, IsRetail = true, SortOrder = 0 },
|
||||||
new PriceType { OrganizationId = orgId, Name = "Оптовая", SortOrder = 1 }
|
new PriceType { OrganizationId = orgId, Name = "Оптовая", SortOrder = 1 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ public record UnitOfMeasureDto(
|
||||||
|
|
||||||
public record PriceTypeDto(
|
public record PriceTypeDto(
|
||||||
Guid Id, string Name, bool IsRequired, bool IsSystem,
|
Guid Id, string Name, bool IsRequired, bool IsSystem,
|
||||||
bool IsDefault, bool IsRetail, int SortOrder);
|
bool IsRetail, int SortOrder);
|
||||||
|
|
||||||
public record StoreDto(
|
public record StoreDto(
|
||||||
Guid Id, string Name, string? Code, string? Address, string? Phone,
|
Guid Id, string Name, string? Code, string? Address, string? Phone,
|
||||||
|
|
@ -64,7 +64,7 @@ public record CurrencyInput(string Code, string Name, string Symbol);
|
||||||
public record UnitOfMeasureInput(string Code, string Name, string? Description = null);
|
public record UnitOfMeasureInput(string Code, string Name, string? Description = null);
|
||||||
public record PriceTypeInput(
|
public record PriceTypeInput(
|
||||||
string Name, bool IsRequired = false,
|
string Name, bool IsRequired = false,
|
||||||
bool IsDefault = false, bool IsRetail = false, int SortOrder = 0);
|
bool IsRetail = false, int SortOrder = 0);
|
||||||
public record StoreInput(
|
public record StoreInput(
|
||||||
string Name, string? Code,
|
string Name, string? Code,
|
||||||
string? Address = null, string? Phone = null, string? ManagerName = null,
|
string? Address = null, string? Phone = null, string? ManagerName = null,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@ public class PriceType : TenantEntity
|
||||||
/// <summary>true — системная запись «Розничная цена», не удаляется и
|
/// <summary>true — системная запись «Розничная цена», не удаляется и
|
||||||
/// IsRequired всегда true. Имя можно переименовать. Сидируется при первом старте.</summary>
|
/// IsRequired всегда true. Имя можно переименовать. Сидируется при первом старте.</summary>
|
||||||
public bool IsSystem { get; set; }
|
public bool IsSystem { get; set; }
|
||||||
public bool IsDefault { get; set; } // цена по умолчанию для новых товаров
|
/// <summary>true — единственная запись, по которой POS касса берёт цену
|
||||||
public bool IsRetail { get; set; } // используется на кассе
|
/// для пробивки чека. Контроллер обеспечивает уникальность: установка
|
||||||
|
/// IsRetail=true сбрасывает её у других записей.</summary>
|
||||||
|
public bool IsRetail { get; set; }
|
||||||
public int SortOrder { get; set; }
|
public int SortOrder { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,24 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace foodmarket.Infrastructure.Persistence.Migrations
|
||||||
|
{
|
||||||
|
/// <summary>price_types.IsDefault удалён — флаг семантически дублировал
|
||||||
|
/// IsSystem (защищённая запись «по умолчанию»). Оставляем IsSystem +
|
||||||
|
/// IsRequired + IsRetail.</summary>
|
||||||
|
public partial class Phase3b_DropPriceTypeIsDefault : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder b)
|
||||||
|
{
|
||||||
|
b.DropColumn(name: "IsDefault", schema: "public", table: "price_types");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder b)
|
||||||
|
{
|
||||||
|
b.AddColumn<bool>(
|
||||||
|
name: "IsDefault", schema: "public", table: "price_types",
|
||||||
|
type: "boolean", nullable: false, defaultValue: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -503,9 +503,6 @@ protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
b.Property<DateTime>("CreatedAt")
|
b.Property<DateTime>("CreatedAt")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
b.Property<bool>("IsDefault")
|
|
||||||
.HasColumnType("boolean");
|
|
||||||
|
|
||||||
b.Property<bool>("IsRequired")
|
b.Property<bool>("IsRequired")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export interface Country {
|
||||||
}
|
}
|
||||||
export interface Currency { id: string; code: string; name: string; symbol: string }
|
export interface Currency { id: string; code: string; name: string; symbol: string }
|
||||||
export interface UnitOfMeasure { id: string; code: string; name: string; description: string | null }
|
export interface UnitOfMeasure { id: string; code: string; name: string; description: string | null }
|
||||||
export interface PriceType { id: string; name: string; isRequired: boolean; isSystem: boolean; isDefault: boolean; isRetail: boolean; sortOrder: number }
|
export interface PriceType { id: string; name: string; isRequired: boolean; isSystem: boolean; isRetail: boolean; sortOrder: number }
|
||||||
export interface Store {
|
export interface Store {
|
||||||
id: string; name: string; code: string | null; address: string | null; phone: string | null;
|
id: string; name: string; code: string | null; address: string | null; phone: string | null;
|
||||||
managerName: string | null; isMain: boolean; isActive: boolean
|
managerName: string | null; isMain: boolean; isActive: boolean
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,10 @@ interface Form {
|
||||||
name: string
|
name: string
|
||||||
isRequired: boolean
|
isRequired: boolean
|
||||||
isSystem: boolean
|
isSystem: boolean
|
||||||
isDefault: boolean
|
|
||||||
isRetail: boolean
|
isRetail: boolean
|
||||||
sortOrder: number
|
sortOrder: number
|
||||||
}
|
}
|
||||||
const blankForm: Form = { name: '', isRequired: false, isSystem: false, isDefault: false, isRetail: false, sortOrder: 0 }
|
const blankForm: Form = { name: '', isRequired: false, isSystem: false, isRetail: false, sortOrder: 0 }
|
||||||
|
|
||||||
export function PriceTypesPage() {
|
export function PriceTypesPage() {
|
||||||
const { data, isLoading, page, setPage, search, setSearch, sortKey, sortOrder, setSort } = useCatalogList<PriceType>(URL)
|
const { data, isLoading, page, setPage, search, setSearch, sortKey, sortOrder, setSort } = useCatalogList<PriceType>(URL)
|
||||||
|
|
@ -62,7 +61,7 @@ export function PriceTypesPage() {
|
||||||
onRowClick={(r) => setForm({
|
onRowClick={(r) => setForm({
|
||||||
id: r.id, name: r.name,
|
id: r.id, name: r.name,
|
||||||
isRequired: r.isRequired, isSystem: r.isSystem,
|
isRequired: r.isRequired, isSystem: r.isSystem,
|
||||||
isDefault: r.isDefault, isRetail: r.isRetail, sortOrder: r.sortOrder,
|
isRetail: r.isRetail, sortOrder: r.sortOrder,
|
||||||
})}
|
})}
|
||||||
columns={[
|
columns={[
|
||||||
{ header: 'Название', sortKey: 'name', cell: (r) => (
|
{ header: 'Название', sortKey: 'name', cell: (r) => (
|
||||||
|
|
@ -120,8 +119,7 @@ export function PriceTypesPage() {
|
||||||
disabled={form.isSystem}
|
disabled={form.isSystem}
|
||||||
onChange={(v) => setForm({ ...form, isRequired: v })}
|
onChange={(v) => setForm({ ...form, isRequired: v })}
|
||||||
/>
|
/>
|
||||||
<Checkbox label="Розничная (используется на кассе)" checked={form.isRetail} onChange={(v) => setForm({ ...form, isRetail: v })} />
|
<Checkbox label="Используется на кассе" checked={form.isRetail} onChange={(v) => setForm({ ...form, isRetail: v })} />
|
||||||
<Checkbox label="По умолчанию" checked={form.isDefault} onChange={(v) => setForm({ ...form, isDefault: v })} />
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
||||||
|
|
@ -396,7 +396,7 @@ export function ProductEditPage() {
|
||||||
<Button type="button" variant="secondary" size="sm" onClick={async () => {
|
<Button type="button" variant="secondary" size="sm" onClick={async () => {
|
||||||
try {
|
try {
|
||||||
const res = await api.post<{ retail: number }>(`/api/catalog/products/${id}/recalc-retail`)
|
const res = await api.post<{ retail: number }>(`/api/catalog/products/${id}/recalc-retail`)
|
||||||
const def = priceTypes.data?.find((pt) => pt.isSystem) ?? priceTypes.data?.find((pt) => pt.isDefault) ?? priceTypes.data?.[0]
|
const def = priceTypes.data?.find((pt) => pt.isSystem) ?? priceTypes.data?.find((pt) => pt.isRetail) ?? priceTypes.data?.[0]
|
||||||
if (def) {
|
if (def) {
|
||||||
setForm((f) => {
|
setForm((f) => {
|
||||||
const has = f.prices.some(p => p.priceTypeId === def.id)
|
const has = f.prices.some(p => p.priceTypeId === def.id)
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ export function ProductsPage() {
|
||||||
const { data, isLoading, page, setPage, search, setSearch, sortKey, sortOrder, setSort } = useCatalogList<Product>(URL, toExtra(filters))
|
const { data, isLoading, page, setPage, search, setSearch, sortKey, sortOrder, setSort } = useCatalogList<Product>(URL, toExtra(filters))
|
||||||
const org = useOrgSettings()
|
const org = useOrgSettings()
|
||||||
const priceTypes = usePriceTypes()
|
const priceTypes = usePriceTypes()
|
||||||
const systemPriceType = priceTypes.data?.find((pt) => pt.isSystem) ?? priceTypes.data?.find((pt) => pt.isDefault) ?? priceTypes.data?.[0]
|
const systemPriceType = priceTypes.data?.find((pt) => pt.isSystem) ?? priceTypes.data?.find((pt) => pt.isRetail) ?? priceTypes.data?.[0]
|
||||||
const showVat = org.data?.showVatEnabledOnProduct ?? false
|
const showVat = org.data?.showVatEnabledOnProduct ?? false
|
||||||
const showService = org.data?.showServiceOnProduct ?? false
|
const showService = org.data?.showServiceOnProduct ?? false
|
||||||
const showMarked = org.data?.showMarkedOnProduct ?? false
|
const showMarked = org.data?.showMarkedOnProduct ?? false
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue