File size: 4,358 Bytes
ddd5681
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/** SmOS booking + payments API (same origin on uvicorn; falls back to :7860). */
window.SmOS_API = (function () {
  const FALLBACK = "http://127.0.0.1:7860";
  const MODULE_ID = (window.SmOS_Module && window.SmOS_Module.id) || "SmOS_CC";

  function bases() {
    const list = [];
    if (location.origin && !location.origin.startsWith("file:")) list.push(location.origin);
    if (!list.includes(FALLBACK)) list.push(FALLBACK);
    return list;
  }

  async function postBooking(payload) {
    const body = { module_id: MODULE_ID, ...payload };
    let lastErr = null;
    for (const base of bases()) {
      try {
        const res = await fetch(`${base}/api/bookings`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(body),
        });
        if (res.ok) return await res.json();
        const err = await res.json().catch(() => ({}));
        const detail = err.detail;
        const msg = Array.isArray(detail)
          ? detail.map((d) => d.msg || d).join("; ")
          : detail || `HTTP ${res.status}`;
        lastErr = new Error(msg);
      } catch (e) {
        lastErr = e;
      }
    }
    throw lastErr || new Error("Booking API unavailable");
  }

  async function createMolliePayment(payload) {
    const body = { module_id: MODULE_ID, ...payload };
    let lastErr = null;
    for (const base of bases()) {
      try {
        const res = await fetch(`${base}/api/modules/SmOS_CC/mollie/create`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(body),
        });
        const data = await res.json().catch(() => ({}));
        if (res.ok) return data;
        const detail = data.detail;
        const msg = Array.isArray(detail)
          ? detail.map((d) => d.msg || d).join("; ")
          : detail || `HTTP ${res.status}`;
        lastErr = new Error(msg);
        if (res.status === 400 || res.status === 503) break;
      } catch (e) {
        lastErr = e;
      }
    }
    throw lastErr || new Error("Mollie checkout unavailable");
  }

  async function mollieStatus(paymentId) {
    let lastErr = null;
    const q = `?payment_id=${encodeURIComponent(paymentId || "")}`;
    for (const base of bases()) {
      try {
        const res = await fetch(`${base}/api/modules/SmOS_CC/mollie/status${q}`, {
          cache: "no-store",
        });
        const data = await res.json().catch(() => ({}));
        if (res.ok) return data;
        const detail = data.detail;
        const msg = Array.isArray(detail)
          ? detail.map((d) => d.msg || d).join("; ")
          : detail || `HTTP ${res.status}`;
        lastErr = new Error(msg);
      } catch (e) {
        lastErr = e;
      }
    }
    throw lastErr || new Error("Mollie status unavailable");
  }

  async function occupiedTables(date) {
    let lastErr = null;
    const q = date ? `?date=${encodeURIComponent(date)}` : "";
    for (const base of bases()) {
      try {
        const res = await fetch(`${base}/api/modules/${MODULE_ID}/tables/occupied${q}`);
        if (res.ok) {
          const data = await res.json();
          return Array.isArray(data.occupied) ? data.occupied.map(String) : [];
        }
        lastErr = new Error(`HTTP ${res.status}`);
      } catch (e) {
        lastErr = e;
      }
    }
    if (lastErr) console.warn("occupiedTables", lastErr);
    return [];
  }

  async function lookupAddresses(postcode) {
    let lastErr = null;
    const q = `?postcode=${encodeURIComponent(postcode || "")}`;
    for (const base of bases()) {
      try {
        const res = await fetch(`${base}/api/modules/${MODULE_ID}/addresses${q}`);
        const data = await res.json().catch(() => ({}));
        if (res.ok) return data;
        const detail = data.detail;
        const msg = Array.isArray(detail)
          ? detail.map((d) => d.msg || d).join("; ")
          : detail || `HTTP ${res.status}`;
        lastErr = new Error(msg);
        if (res.status === 400 || res.status === 404 || res.status === 503) break;
      } catch (e) {
        lastErr = e;
      }
    }
    throw lastErr || new Error("Address lookup unavailable");
  }

  return {
    postBooking,
    createMolliePayment,
    mollieStatus,
    occupiedTables,
    lookupAddresses,
    bases,
    moduleId: MODULE_ID,
  };
})();