Recoma
← Documentație API

Recoma în WooCommerce

Trei cârlige în functions.php (sau, mai bine, într-un plugin mic al tău). Nimic din ce urmează nu atinge baza de date WooCommerce.

Pune cheia în wp-config.php, nu în cod: define('RECOMA_KEY', 'rk_live_…');. Un fișier de temă ajunge în Git, în backup-uri și uneori într-un ticket de suport.

1. Validare la aplicarea codului

WooCommerce are propriile cupoane, dar codurile Recoma nu există în WooCommerce — deci le interceptăm înainte ca Woo să caute în tabelul lui și să spună „cupon inexistent”.

functions.php
function recoma_call($path, $body = null, $headers = []) {
    $args = [
        'timeout' => 8,
        'headers' => array_merge([
            'Authorization' => 'Bearer ' . RECOMA_KEY,
            'Content-Type'  => 'application/json',
        ], $headers),
    ];
    if ($body !== null) {
        $args['method'] = 'POST';
        $args['body']   = wp_json_encode($body);
        $res = wp_remote_post('https://api.recoma.ro' . $path, $args);
    } else {
        $res = wp_remote_get('https://api.recoma.ro' . $path, $args);
    }
    if (is_wp_error($res)) return null;
    return json_decode(wp_remote_retrieve_body($res), true);
}

add_filter('woocommerce_get_shop_coupon_data', function ($data, $code) {
    $subtotal = WC()->cart ? WC()->cart->get_subtotal() : 0;
    $answer = recoma_call('/v1/codes/' . rawurlencode($code) . '/validate', [
        'order_value' => $subtotal,
        // Numai pentru codurile cu limită per client.
        'customer_ref' => is_user_logged_in() ? (string) get_current_user_id() : null,
    ]);

    // Nu e cod Recoma (sau API-ul nu răspunde): lăsăm Woo să-și caute cuponul lui.
    if (!$answer || empty($answer['valid'])) return $data;

    $coupon = new WC_Coupon($code);
    $d = $answer['discount'];

    if ($d['kind'] === 'percent') {
        $coupon->set_discount_type('percent');
        $coupon->set_amount($d['value']);
        // Woo nu are plafon pe procent; dacă există unul, trecem pe sumă fixă.
        if (!empty($answer['applies_to']) &&
            $d['max_discount_amount'] !== null &&
            $answer['applies_to']['discount_amount'] >= $d['max_discount_amount']) {
            $coupon->set_discount_type('fixed_cart');
            $coupon->set_amount($answer['applies_to']['discount_amount']);
        }
    } elseif ($d['kind'] === 'fixed') {
        $coupon->set_discount_type('fixed_cart');
        $coupon->set_amount($d['value']);
    } else { // free_shipping
        $coupon->set_discount_type('fixed_cart');
        $coupon->set_amount(0);
        $coupon->set_free_shipping(true);
    }

    if ($d['min_order_value'] !== null) {
        $coupon->set_minimum_amount($d['min_order_value']);
    }
    return $coupon;
}, 10, 2);

Dacă vrei să explici de ce nu se aplică un cod (expirat, epuizat, sub minimul de comandă), citește reason din răspuns și afișează propriul tău mesaj, în limba clientului. Mesajele noastre sunt în engleză și scrise pentru dezvoltatori.

2. Înregistrarea comenzii

La plasarea comenzii. Numărul comenzii servește și drept cheie de idempotență — dacă un webhook se reia sau clientul dă refresh pe pagina de mulțumire, nu se plătește comision de două ori.

functions.php
add_action('woocommerce_checkout_order_processed', function ($order_id) {
    $order = wc_get_order($order_id);
    foreach ($order->get_coupon_codes() as $code) {
        $result = recoma_call(
            '/v1/codes/' . rawurlencode($code) . '/redeem',
            [
                // Valoarea produselor ÎNAINTE de reducere, fără transport.
                'order_value'  => (float) $order->get_subtotal(),
                'order_ref'    => (string) $order->get_order_number(),
                'customer_ref' => $order->get_billing_email(),
            ],
            ['Idempotency-Key' => 'wc-' . $order_id]
        );
        if ($result && !empty($result['id'])) {
            // Păstrează-l: îți trebuie ca să poți anula la retur.
            $order->update_meta_data('_recoma_redemption_id', $result['id']);
            $order->save();
        }
    }
});

3. Retururi

Comisionul se întoarce, iar codul recuperează folosirea.

functions.php
add_action('woocommerce_order_status_refunded', function ($order_id) {
    $order = wc_get_order($order_id);
    $id = $order->get_meta('_recoma_redemption_id');
    if (!$id) return;
    recoma_call('/v1/redemptions/' . $id . '/void', ['reason' => 'retur WooCommerce']);
});

Dacă luna de decontare s-a închis deja, primești 409 month_locked. Nu e o eroare de integrare — e regula după care se închid lunile. Corectarea se face în doi, din aplicație.

De verificat înainte de producție

Ce trimiți ca order_value. Produsele, înainte de reducere, fără transport. get_subtotal() este de obicei exact asta; dacă lucrezi cu prețuri cu TVA inclus, decide o dată dacă baza de comision e cu sau fără TVA și rămâi la ea — apare pe factura cuiva.

Ce faci când API-ul nu răspunde. În codul de mai sus, coșul continuă fără reducere. Alege conștient: preferi să pierzi o reducere sau o comandă?