Skip to main content

FirsatGO POS Entegrasyonu — HİZMET (Service) Sektörü Developer Dokümanı

Genel Bakış

FirsatGO bir talep ağı (Getir / Trendyol-GO konumu), POS entegratörünüz ise FirsatGO sözleşmesine uyan tarafdır. Hizmet (service) sektörü, platformdaki diğer sektörlerden temelde farklıdır: burada kalemli-sipariş / sepet / fiş kavramı YOKTUR. Akış randevu ve iş-emri (work order) tabanlıdır: müşteri bir sağlayıcıdan iş ister → sağlayıcı teklif verir (veya sabit-fiyatlı katalog kalemi anında book edilir) → kabul → iş emri açılır → randevu/saha/teslimat aşamaları → müşteri kabulü → ödeme.

KRİTİK SEKTÖR-FARKI: Hizmet siparişleri Order akışından GEÇMEZ. Kendi state-machine'i service-engine'dedir. FirsatGO'nun POS'a sipariş gönderdiği POST {posBase}/orders webhook'u ve POS→FG sipariş pull/status yüzeyleri (B) hizmet sektöründe kullanılmaz. Kod tarafında bunun teyidi nettir: integrations/ ve external-api/ modüllerinde hiçbir iş-emri/talep referansı yoktur. food/retail kalemli-sipariş modeli hizmette UYGULANMAZ.

Sektör motoru: engine=service. Profiller: field_service (saha), professional_service (profesyonel), hybrid_service (hibrit). İşletmenin sector alanı services olmalıdır (fail-closed doğrulama).


Sipariş Yaşam-Döngüsü (Hizmet State-Machine'i)

Hizmette tek bir "sipariş durumu" yoktur; üç ayrı varlığın durum makineleri zincirleme çalışır: ServiceRequest (talep) → ServiceQuote (teklif) → WorkOrder (iş emri).

1) Talep — ServiceRequest.status

DurumAnlam
openMüşteri talep oluşturdu (fiyat henüz yok)
quotedSağlayıcı en az bir teklif verdi
acceptedTeklif kabul edildi → iş emri açıldı
closedTalep kapatıldı
cancelledTalep iptal edildi

2) Teklif — ServiceQuote.status

DurumAnlam
pendingAktif teklif, müşteri yanıtı bekleniyor
acceptedMüşteri kabul etti → iş emri açıldı
rejectedMüşteri reddetti
expiredGeçerlilik süresi (valid_until) doldu
revisedSağlayıcı yeni revizyon (revision_no++) verdi, bu teklif geçersizleşti

3) İş Emri — WorkOrder.status (asıl yürütme makinesi)

DurumAnlamGeçebileceği durumlar
scheduledİş emri açıldı / randevu planlandıin_progress, cancelled
in_progressİş başladı (sağlayıcı ilerletti)awaiting_acceptance, cancelled
awaiting_acceptanceTamamlandı, müşteri onayı bekleniyorin_progress (geri), completed, cancelled
completedMüşteri kabul etti → ödeme aşamasına hazır (terminal)
cancelledİptal (terminal). appointment_at $unset → slot serbest kalır

Geçiş aktörleri: scheduled→in_progress→awaiting_acceptance ve cancel sağlayıcı tarafından (PUT /work-orders/:id/transition); awaiting_acceptance→completed müşteri kabulüyle (POST /work-orders/:id/accept).

Para koruması: payment_status unpaid değilse (yani processing/partial/paid) iş emri doğrudan cancelled yapılamaz — önce iade akışı çalışmalıdır.

Ödeme durumu — WorkOrder.payment_status

unpaid | processing (tam-ödeme tahsilatı uçuşta, atomik claim) | partial (bazı milestone'lar ödendi) | paid | refunded.


Sektöre-Özel Sipariş Alanları (yalnız hizmette geçerli)

Hizmette Order payload'u / fulfillment{} / items[] bloğu YOKTUR. Onun yerine iş-emri (work order) ve bağlı teklif alanları geçerlidir.

WorkOrder alanları

AlanTipAçıklama
quote_idObjectIdKaynak teklif
request_idObjectIdKaynak talep
merchant_idObjectIdSağlayıcı işletme
customer_idObjectIdMüşteri
amountnumber (₺)Kabul edilen teklif tutarı (saf hizmet bedeli)
statusenumİş emri durumu (yukarıdaki tablo)
appointment_atDateRandevu zamanı (slot rezervasyonu; dakikaya yuvarlanır)
status_history[]{status, actor, at, note}Durum geçmişi
before_photos[] / after_photos[]string[]İş öncesi/sonrası fotoğraflar
acceptance{accepted_at, note}Müşteri kabulü
payment_statusenumunpaid/processing/partial/paid/refunded
milestones[]{title, amount, status, due_date, paid_at}Aşama bazlı ödeme planı (professional/hybrid). status: pending/processing/paid
deliverables[]{name, url, note, uploaded_at}Teslim edilen çıktılar (professional)
site_visit{scheduled_at, completed_at, notes, photos[]}Saha ziyareti (field/hybrid)

ServiceQuote.line_items[] (food items[]'ın hizmet karşılığı)

AlanTipAçıklama
descriptionstringKalem açıklaması (örn. "İşçilik", "Malzeme")
quantitynumberAdet
unit_pricenumber (₺)Birim fiyat

Teklif ayrıca: amount (toplam), notes, valid_until, revision_no, status.

Not: line_items food/retail kalemli-siparişten farklıdır — bunlar fiş kalemi değil, teklif kalemleridir; POS'a sipariş olarak gönderilmez, FirsatGO içinde teklif round-trip'inde kullanılır.

Örnek iş-emri JSON

{
"_id": "665f0a...",
"quote_id": "665f09...",
"request_id": "665f08...",
"merchant_id": "664c...",
"customer_id": "6612...",
"amount": 2500.00,
"status": "in_progress",
"appointment_at": "2026-07-02T11:00:00.000Z",
"payment_status": "unpaid",
"milestones": [
{ "title": "Keşif + avans", "amount": 1000, "status": "paid", "due_date": "2026-07-01T00:00:00.000Z" },
{ "title": "Teslim", "amount": 1500, "status": "pending", "due_date": "2026-07-10T00:00:00.000Z" }
],
"site_visit": { "scheduled_at": "2026-07-02T11:00:00.000Z", "notes": "2. kat, kombi dairesi" },
"status_history": [
{ "status": "scheduled", "actor": "customer", "at": "2026-06-28T09:00:00.000Z" },
{ "status": "in_progress", "actor": "merchant", "at": "2026-07-02T11:05:00.000Z" }
]
}

Katalog / Ürün

Hizmette "ürün" = ServiceListing (sağlayıcının yayınladığı sunduğu hizmet). food catalog.product şeklinden farklıdır.

AlanTipAçıklama
merchant_idObjectIdSağlayıcı işletme
titlestringHizmet başlığı
descriptionstring?Açıklama
service_typestring?Hizmet türü (örn. tesisat, sac_kesim)
pricing_modeenumfixed (sabit fiyat → anında booking + ödeme) veya quote (teklif round-trip'i)
base_pricenumber?pricing_mode=fixed için zorunlu (>0)
duration_minnumber?Tahmini süre (dakika)
images[]string[]Görseller
is_activebooleanYayın durumu

Uygunluk takvimi — ProviderAvailability (sağlayıcı başına tek kayıt; food'da karşılığı yok):

AlanAçıklama
slot_duration_minSlot süresi (dk, varsayılan 60, min 5)
weekly[]7 eleman, JS getDay() indeksli (0=Pazar..6=Cumartesi). Her gün: {enabled, open "HH:MM", close "HH:MM"}
blackout_dates[]Kapalı günler (YYYY-MM-DD listesi)

Müsait slotlar = çalışma saatleri − dolu randevular − geçmiş saatler (GET /service-providers/:merchantId/slots?date=YYYY-MM-DD).


Akış Notları (hizmete özgü kurallar)

  • Sipariş-webhook'u yerine iş-emri akışı. POS entegratörü için bu sektör, food/retail'den temelden farklıdır: FirsatGO size kalemli-sipariş webhook'u göndermez; ortak sözleşmedeki finansal blok (original_subtotal, delivery_fee, tax, *_minor, coupon_code, delivery_address, fulfillment{}...) ve durum olayları (order.created, store.open...) hizmette uygulanmaz. Akış FirsatGO içinde randevu/iş-emri state-machine'i ile yürür.
  • İki giriş yolu:
    1. quote modu: müşteri talep açar (open) → sağlayıcı teklif verir (quoted/pending) → müşteri kabul eder → iş emri (scheduled) açılır. Teklif revize edilebilir (önceki teklifler revised, revision_no artar).
    2. fixed modu: müşteri sabit-fiyatlı katalog kalemini book eder → talep + otomatik-kabul teklif + iş emri (scheduled, amount=base_price) tek seferde oluşur; teklif round-trip'i yoktur.
  • Slot rezervasyonu randevulu (appointment_at) iş emriyle gerçekleşir. Bir sağlayıcıda aynı randevu saatine tek aktif iş emri olabilir (unique partial index; eşzamanlı çift-rezervasyon → DB hatası → 400). appointment_at dakikaya yuvarlanır. İptalde appointment_at kaldırılır → slot serbest kalır. Slot hesabı sunucu yerel saat dilimine göredir (deploy'da TZ pinlenmeli).
  • Settlement work-order bazlıdır ve saf hizmet bedeli üzerindendir: amount → komisyon kesilir → satıcı net hakediş. Teslimat ücreti ve vergi YOKTUR (food fişindeki delivery_fee/tax kalemleri burada yer almaz). Ödeme completed öncesi/sonrası müşteri tarafından yapılır (POST /payments/work-orders/:id/pay), paid olunca settlement işler.
  • Milestone (aşama) ödemesi (professional/hybrid): iş emri tutarı aşamalara bölünür; her aşama müşteri tarafından ayrı ödenir (POST /payments/work-orders/:id/milestones/:milestoneId/pay). Aşama tutarları toplamı iş emri amount'unu aşamaz. Her aşama ödemesi kendi settlement'ını üretir; kısmen ödenmiş iş emri payment_status=partial.
  • İade settlement'ı ters-kayıtla geri alır (tam veya milestone bazlı). Ödemesi alınmış iş emri doğrudan iptal edilemez; önce iade.
  • IDOR / tenant-izolasyon: her uç sahiplikle scoped — müşteri yalnız kendi talep/teklif/iş-emrini, sağlayıcı yalnız kendi işletmesinin kayıtlarını görür.
  • Profil-bazlı yetenekler: site_visit (saha ziyareti) → field/hybrid; deliverables (teslim çıktıları) → professional; milestones → professional/hybrid.

Örnek (gerçekçi hizmet akış payload'ları)

Talep (müşteri → FG):

{
"merchant_id": "664c1f...",
"service_type": "tesisat",
"title": "Kombi bakımı ve petek temizliği",
"description": "3+1 daire, 8 petek; kombi 5 yıllık.",
"budget": 3000,
"address": { "street": "Bağdat Cad. No:12", "district": "Kadıköy", "city": "İstanbul" },
"preferred_date": "2026-07-02T11:00:00.000Z",
"attachments": ["https://cdn.firsatgo.com/req/abc.jpg"]
}

Teklif (sağlayıcı → FG):

{
"amount": 2500,
"line_items": [
{ "description": "Kombi bakım işçiliği", "quantity": 1, "unit_price": 1500 },
{ "description": "Petek temizliği (8 adet)", "quantity": 8, "unit_price": 125 }
],
"notes": "Yedek parça gerekirse ayrıca bilgilendirilecektir.",
"valid_until": "2026-07-01T23:59:00.000Z"
}

Kabul edilip açılan iş emri (FG state):

{
"_id": "665f0a...",
"quote_id": "665f09...",
"request_id": "665f08...",
"merchant_id": "664c1f...",
"customer_id": "6612aa...",
"amount": 2500,
"status": "scheduled",
"appointment_at": "2026-07-02T11:00:00.000Z",
"payment_status": "unpaid",
"site_visit": { "scheduled_at": "2026-07-02T11:00:00.000Z", "notes": "Kapıcıdan anahtar alınacak" },
"status_history": [
{ "status": "scheduled", "actor": "customer", "at": "2026-06-28T10:15:00.000Z" }
]
}

İlgili kaynak dosyalar (as-built doğrulama):

  • /home/firsatgo/firsatgo-backendv2/src/service-engine/schemas/work-order.schema.ts
  • /home/firsatgo/firsatgo-backendv2/src/service-engine/schemas/service-request.schema.ts
  • /home/firsatgo/firsatgo-backendv2/src/service-engine/schemas/service-quote.schema.ts
  • /home/firsatgo/firsatgo-backendv2/src/service-engine/schemas/service-listing.schema.ts
  • /home/firsatgo/firsatgo-backendv2/src/service-engine/schemas/provider-availability.schema.ts
  • /home/firsatgo/firsatgo-backendv2/src/service-engine/service-engine.service.ts (state-machine, slot/randevu, milestone/deliverable/site_visit)
  • /home/firsatgo/firsatgo-backendv2/src/payments/ledger.service.ts (work-order + milestone settlement; teslimat/vergi yok)
  • /home/firsatgo/firsatgo-backendv2/src/payments/payments.service.ts (payWorkOrder/payMilestone)

Sektör-farkı teyidi: integrations/ ve external-api/ modüllerinde iş-emri/talep/listing referansı yoktur — hizmet siparişleri POS order-webhook yüzeyine hiç dokunmaz.