Sprzedaż i towary na sprzedaż
Te zasoby obsługują moduł Sprzedaż: towary, takie jak karty pamięci, akumulatory czy taśma gaffer, które wypożyczalnia sprzedaje z ewidencją stanów obok wynajmu.
RequiplyError ze status403 i reasonfeature_disabled (selling_disabled dla klucza publicznego).| Metoda | Klucz tajny | Klucz publiczny |
|---|---|---|
saleItems.list(), saleItems.get() | Tak | Tylko aktywne towary, gdy organizacja sprzedaje klientom |
saleLines w pricing.quote() i bookings.create() | Tak | Tak, w granicach stanu magazynowego, gdy organizacja sprzedaje klientom |
sales.list(), sales.get(), sales.create() | Tak | Nie |
Towary na sprzedaż są oddzielone od pozycji do wynajęcia: inventory.list(), dostępność i categories.list() nigdy ich nie zwracają.
Z kluczem publicznym
Sklep internetowy może pokazywać towary na sprzedaż i pozwalać klientom dodawać je do zapytania o rezerwację, tak jak portal klienta robi to w kroku Produkty do zakupu. Klucz publiczny ma do nich dostęp tylko wtedy, gdy organizacja sprzedaje klientom, co wymaga spełnienia wszystkich trzech warunków:
- funkcja Sprzedaż włączona w planie Advanced, jak wyżej;
- włączona opcja Sprzedaż towarów w ustawieniach portalu klienta;
- co najmniej jeden niezarchiwizowany towar na sprzedaż.
W przeciwnym razie wywołanie zgłasza 403 z reason selling_disabled, więc sklep internetowy może ukryć sekcję z towarami.
Z kluczem publicznym:
saleItems.list()zwraca tylko aktywne towary, niezależnie od wartościfilter.barcodeipurchaseCostmają zawsze wartośćnull.saleItems.get()zwraca404dla zarchiwizowanego towaru, asoldUnits30d,revenue30disoldUnitsTotalmają wartość0.saleLinesnie może prosić o więcej niżstockOnHand. Pozycja ponad stan zgłasza409zreasonout_of_stock.data.saleItemIdwskazuje towar, adata.availableQuantitymówi, ile zostało (0, gdy towar jest wyprzedany).
try {
await requiply.pricing.quote({ startDate, endDate, items, saleLines });
} catch (error) {
if (error instanceof RequiplyError && error.reason === 'out_of_stock') {
showNotice(`Only ${error.data?.availableQuantity} left`);
} else if (error instanceof RequiplyError && error.reason === 'selling_disabled') {
hideGoodsSection();
} else {
throw error;
}
}
saleItems.list()
saleItems.list(
params?: SaleItemsListParams,
options?: RequiplyRequestOptions,
): Promise<SaleItemsListResponse>
Parametry opcjonalne: search (nazwa, SKU lub kod kreskowy), category (identyfikator kategorii), filter (domyślnie active, a także archived lub all; klucze publiczne zawsze dostają active), limit (od 1 do 100, domyślnie 25) i cursor.
const { items, nextCursor } = await requiply.saleItems.list({ search: 'battery' });
for (const item of items) {
console.log(item.name, item.salePrice, item.currency, item.stockOnHand);
}
| Pole | Co zawiera |
|---|---|
id, name, sku, barcode | Towar. sku i barcode mogą mieć wartość null. Dla klucza publicznego barcode ma zawsze wartość null. |
categoryId, categoryName, imageUrl | Mogą mieć wartość null. |
salePrice, currency | Stała cena za sztukę w walucie organizacji. |
stockOnHand | Liczba sztuk na półce. Może być ujemna, gdy sprzedaż przekroczyła zapisany stan. |
purchaseCost | Koszt netto za sztukę albo null, chyba że klucz może zarządzać stanem magazynowym. Dla klucza publicznego zawsze null. |
isArchived | Zarchiwizowanych towarów nie można sprzedawać. |
saleItems.get()
saleItems.get(
saleItemId: string,
options?: RequiplyRequestOptions,
): Promise<SaleItemResponse>
Zwraca saleItem z powyższymi polami oraz soldUnits30d, revenue30d i soldUnitsTotal.
const { saleItem } = await requiply.saleItems.get(itemId);
console.log(saleItem.soldUnits30d, saleItem.revenue30d);
sales.list()
sales.list(
params?: SalesListParams,
options?: RequiplyRequestOptions,
): Promise<SalesListResponse>
Wymienia sprzedaże od najnowszej, zarówno samodzielne, jak i w ramach rezerwacji. Filtry opcjonalne:
| Parametr | Działanie |
|---|---|
kind | standalone lub booking. |
status | completed lub cancelled. |
unpaid | true dla samodzielnych sprzedaży, które nie są jeszcze w pełni opłacone. |
clientId | Sprzedaże jednego klienta. |
soldFrom, soldTo | Daty z godziną w formacie ISO 8601. |
search | Numer sprzedaży, nazwa klienta, e-mail lub telefon, nazwa towaru lub SKU. |
limit, cursor | Rozmiar strony (od 1 do 100, domyślnie 25) i nextCursor poprzedniej strony. |
const { sales, currency } = await requiply.sales.list({ kind: 'standalone', unpaid: true });
Każda sprzedaż ma id, saleOrgId (numer sprzedaży, który pracownicy widzą w aplikacji), status, soldAt, total, returnedTotal, net (suma pomniejszona o zwroty), paidAmount, balance, paymentMethod, paidAt, note, klienta, rezerwację, do której należy (reservationId, reservationOrgId), itemCount i itemsLabel. balance to kwota, której samodzielna sprzedaż nadal wymaga. Dla sprzedaży w ramach rezerwacji ma zawsze wartość 0, bo płaci się za nią w rezerwacji.
sales.get()
sales.get(
id: string | number,
params?: { idKind?: 'internal' | 'org' },
options?: RequiplyRequestOptions,
): Promise<SaleResponse>
id to UUID sprzedaży albo numer sprzedaży z aplikacji z idKind: 'org'.
const { sale } = await requiply.sales.get(12, { idKind: 'org' });
Sprzedaż zawiera też lines (towar, ilość, returnedQuantity, unitPrice, lineTotal), returns i payments. W przypadku sprzedaży w ramach rezerwacji payments to płatności rezerwacji, bo rezerwacja pobiera opłatę za wynajem i towary w jednej płatności.
sales.create()
sales.create(
input: SaleCreateInput,
options?: RequiplyRequestOptions,
): Promise<SaleCreateResponse>
Rejestruje samodzielną sprzedaż, tak jak Nowa sprzedaż w aplikacji.
const { sale, stockWarnings, payment } = await requiply.sales.create({
lines: [{ saleItemId: itemId, quantity: 2 }],
client: { name: 'Alex', email: 'customer@example.com' },
paymentMethod: 'monobank',
note: 'Counter sale',
});
if (payment?.paymentUrl) console.log('Pay here:', payment.paymentUrl);
| Pole | Zasady |
|---|---|
lines | Wymagane. Od 1 do 100 towarów, każdy najwyżej raz, z ilością będącą liczbą całkowitą większą od zera. Każda pozycja jest sprzedawana po cenie salePrice towaru. |
clientId lub client | Opcjonalne. client jest dopasowywany po adresie e-mail, potem po telefonie, a gdy żaden nie pasuje, zostaje utworzony. |
paymentMethod | payOnPickup (domyślnie) albo monobank, liqpay, wayforpay lub stripe przy aktywnej integracji. liqpay wymaga klienta z adresem e-mail. |
soldAt | ISO 8601. Domyślnie bieżący moment. |
note | Do 2000 znaków. |
Stan magazynowy spada od razu. Sprzedaż może zejść ze stanem poniżej zera: nadal zostaje zarejestrowana, a stockWarnings wymienia każdy taki towar z jego stockOnHand i stanem after po sprzedaży. payment to oczekująca płatność, od której zaczyna się sprzedaż, z paymentUrl dla metody online.
Odrzucona sprzedaż zgłasza RequiplyError z reason, takim jak sale_item_archived, payment_method_unavailable lub client_email_required. Pełną listę zawiera Obsługa błędów.
Towary w rezerwacji
pricing.quote() i bookings.create() przyjmują saleLines, aby sprzedać towary razem z wynajmem:
const quote = await requiply.pricing.quote({
startDate: '2026-07-01T10:00:00',
endDate: '2026-07-03T18:00:00',
items: [{ groupId: cameraKitId, quantity: 1 }],
saleLines: [{ saleItemId: memoryCardId, quantity: 2 }],
});
console.log(quote.saleSubtotal, quote.lineSaleItems[0]?.stockAfter);
- Klucz tajny może sprzedawać poniżej zerowego stanu, tak jak pracownicy w aplikacji. Klucz publiczny nie może: zobacz Z kluczem publicznym.
- Towary są sprzedawane po cenie katalogowej i nigdy nie są objęte rabatem ani korektą. Ich suma to
saleSubtotal, już uwzględniona wtotal. lineSaleItemspokazuje każdy towar zstockOnHandistockAfter, więc możesz ostrzec, zanim stan spadnie poniżej zera.- W
bookings.create()stan magazynowy spada po utworzeniu rezerwacji i wraca, jeśli rezerwacja zostanie anulowana. Suma za towary jest doliczana dototalCostrezerwacji i jej płatności. bookings.get()zwraca towary jakosaleItems, a ich sprzedaż jakosaleId.
Aby zmienić towary w istniejącej rezerwacji, użyj w aplikacji opcji Sprzedaż towarów w rezerwacji.