summaryrefslogtreecommitdiff
path: root/src/backenddb/pg_insert_transfer_details.sql
blob: 1650d157783f19cb0e4af49bddec2ad844b38366 (plain)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
--
-- This file is part of TALER
-- Copyright (C) 2024 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
-- Foundation; either version 3, or (at your option) any later version.
--
-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with
-- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
--


CREATE OR REPLACE FUNCTION merchant_do_insert_transfer_details (
  IN in_instance_id TEXT,
  IN in_exchange_url TEXT,
  IN in_payto_uri TEXT,
  IN in_wtid BYTEA,
  IN in_execution_time INT8,
  IN in_exchange_pub BYTEA,
  IN in_exchange_sig BYTEA,
  IN in_total_amount taler_amount_currency,
  IN in_wire_fee taler_amount_currency,
  IN ina_coin_values taler_amount_currency[],
  IN ina_deposit_fees taler_amount_currency[],
  IN ina_coin_pubs BYTEA[],
  IN ina_contract_terms BYTEA[],
  OUT out_no_instance BOOL,
  OUT out_no_account BOOL,
  OUT out_no_exchange BOOL,
  OUT out_duplicate BOOL,
  OUT out_conflict BOOL)
LANGUAGE plpgsql
AS $$
DECLARE
  my_merchant_id INT8;
  my_signkey_serial INT8;
  my_credit_serial INT8;
  my_affected_orders RECORD;
  i INT8;
  curs CURSOR (arg_coin_pub BYTEA) FOR
    SELECT mcon.deposit_confirmation_serial,
           mcon.order_serial
      FROM merchant_deposits dep
      JOIN merchant_deposit_confirmations mcon
        USING (deposit_confirmation_serial)
      WHERE dep.coin_pub=arg_coin_pub;
  ini_coin_pub BYTEA;
  ini_contract_term BYTEA;
  ini_coin_value taler_amount_currency;
  ini_deposit_fee taler_amount_currency;
BEGIN

-- Which instance are we using?
SELECT merchant_serial
  INTO my_merchant_id
  FROM merchant_instances
 WHERE merchant_id=in_instance_id;

IF NOT FOUND
THEN
  out_no_instance=TRUE;
  out_no_account=FALSE;
  out_no_exchange=FALSE;
  out_duplicate=FALSE;
  out_conflict=FALSE;
  RETURN;
END IF;
out_no_instance=FALSE;

-- Determine account that was credited.
SELECT credit_serial
  INTO my_credit_serial
  FROM merchant_transfers
 WHERE exchange_url=in_exchange_url
     AND wtid=in_wtid
     AND account_serial=
     (SELECT account_serial
        FROM merchant_accounts
       WHERE payto_uri=in_payto_uri
         AND exchange_url=in_exchange_url
         AND merchant_serial=my_merchant_id);

IF NOT FOUND
THEN
  out_no_account=TRUE;
  out_no_exchange=FALSE;
  out_duplicate=FALSE;
  out_conflict=FALSE;
  RETURN;
END IF;
out_no_account=FALSE;

-- Find exchange sign key
SELECT signkey_serial
  INTO my_signkey_serial
  FROM merchant_exchange_signing_keys
 WHERE exchange_pub=in_exchange_pub
   ORDER BY start_date DESC
   LIMIT 1;

IF NOT FOUND
THEN
  out_no_exchange=TRUE;
  out_conflict=FALSE;
  out_duplicate=FALSE;
  RETURN;
END IF;
out_no_exchange=FALSE;

-- Add signature first, check for idempotent request
INSERT INTO merchant_transfer_signatures
  (credit_serial
  ,signkey_serial
  ,credit_amount
  ,wire_fee
  ,execution_time
  ,exchange_sig)
  VALUES
   (my_credit_serial
   ,my_signkey_serial
   ,in_total_amount
   ,in_wire_fee
   ,in_execution_time
   ,in_exchange_sig)
  ON CONFLICT DO NOTHING;

IF NOT FOUND
THEN
  PERFORM 1
    FROM merchant_transfer_signatures
    WHERE credit_serial=my_credit_serial
      AND signkey_serial=my_signkey_serial
      AND credit_amount=in_credit_amount
      AND wire_fee=in_wire_fee
      AND execution_time=in_execution_time
      AND exchange_sig=in_exchange_sig;
  IF FOUND
  THEN
    -- duplicate case
    out_duplicate=TRUE;
    out_conflict=FALSE;
    RETURN;
  END IF;
  -- conflict case
  out_duplicate=FALSE;
  out_conflict=TRUE;
  RETURN;
END IF;

out_duplicate=FALSE;
out_conflict=FALSE;


FOR i IN 1..array_length(ina_coin_pubs,1)
LOOP
  ini_coin_value=ina_coin_values[i];
  ini_deposit_fee=ina_deposit_fees[i];
  ini_coin_pub=ina_coin_pubs[i];
  ini_contract_term=ina_contract_terms[i];

  INSERT INTO merchant_transfer_to_coin
    (deposit_serial
    ,credit_serial
    ,offset_in_exchange_list
    ,exchange_deposit_value
    ,exchange_deposit_fee)
    SELECT
        dep.deposit_serial
       ,my_credit_serial
       ,i
       ,ini_coin_value
       ,ini_deposit_fee
      FROM merchant_deposits dep
      JOIN merchant_deposit_confirmations dcon
        USING (deposit_confirmation_serial)
      JOIN merchant_contract_terms cterm
        USING (order_serial)
      WHERE dep.coin_pub=ini_coin_pub
        AND cterm.h_contract_terms=ini_contract_term
        AND cterm.merchant_serial=my_merchant_id;

  RAISE NOTICE 'iterating over affected orders';
  OPEN curs (arg_coin_pub:=ini_coin_pub);
  LOOP
    FETCH NEXT FROM curs INTO my_affected_orders;
    EXIT WHEN NOT FOUND;

    RAISE NOTICE 'checking affected order for completion';

    -- First, check if deposit confirmation is done.
    UPDATE merchant_deposit_confirmations
       SET wire_pending=FALSE
     WHERE (deposit_confirmation_serial=my_affected_orders.deposit_confirmation_serial)
       AND NOT EXISTS
       (SELECT 1
          FROM merchant_deposits md
          LEFT JOIN merchant_deposit_to_transfer mdtt
            USING (deposit_serial)
          WHERE md.deposit_confirmation_serial=my_affected_orders.deposit_confirmation_serial
            AND mdtt.wtid IS NULL);
    -- wtid will be NULL due to LEFT JOIN
    -- if we do not have an entry in mdtt for the deposit
    -- and thus some entry in md was not yet wired.

    IF FOUND
    THEN
      -- Also update contract terms, if all (other) associated
      -- deposit_confirmations are also done.

      UPDATE merchant_contract_terms
         SET wired=TRUE
       WHERE (order_serial=my_affected_orders.order_serial)
         AND NOT EXISTS
         (SELECT 1
            FROM merchant_deposit_confirmations mdc
             WHERE mdc.wire_pending
               AND mdc.order_serial=my_affected_orders.order_serial);
    END IF;

  END LOOP; -- END curs LOOP
  CLOSE curs;
END LOOP; -- END FOR loop

END $$;