🎫 Reglas de carrito programaticas — cupones y descuentos
Actualizado: 2025-01-15
Uso real
Este patron se usa en modulos de fidelizacion, campanas de email marketing, welcome coupons para nuevos registros, y programas de afiliados.
#CartRule: la clase clave
En PrestaShop, los cupones y reglas de carrito son instancias de CartRule. Esta clase extiende ObjectModel y controla: tipo de descuento, condiciones de activacion, restricciones por grupo/producto/categoria, fechas de validez, y usos maximos.
#Crear cupon de porcentaje
Cupon 15% para un cliente especifico
php
<?php
/**
* Crear cupon de 15% de descuento
* Ejemplo: regalo de bienvenida tras registro
*/
function createWelcomeCoupon(int $idCustomer): ?CartRule
{
$customer = new Customer($idCustomer);
if (!Validate::isLoadedObject($customer)) {
return null;
}
$cartRule = new CartRule();
// Codigo unico del cupon (lo que el cliente introduce en checkout)
$cartRule->code = 'WELCOME-' . strtoupper(Tools::passwdGen(8));
// Nombre del cupon (multilang, visible en BO y emails)
foreach (Language::getLanguages(true) as $lang) {
$cartRule->name[$lang['id_lang']] = 'Bienvenida -15% para ' . $customer->firstname;
}
// Tipo de descuento: porcentaje
$cartRule->reduction_percent = 15.00;
$cartRule->reduction_tax = true; // Descuento sobre precio con IVA
// Validez: 30 dias desde hoy
$cartRule->date_from = date('Y-m-d H:i:s');
$cartRule->date_to = date('Y-m-d H:i:s', strtotime('+30 days'));
// Restriccion: solo para este cliente
$cartRule->id_customer = $idCustomer;
// Uso: 1 vez por cliente, 1 uso total
$cartRule->quantity = 1; // Usos totales
$cartRule->quantity_per_user = 1; // Usos por cliente
// Minimo de compra: 30 EUR
$cartRule->minimum_amount = 30.00;
$cartRule->minimum_amount_tax = true;
$cartRule->minimum_amount_currency = (int) Configuration::get('PS_CURRENCY_DEFAULT');
$cartRule->minimum_amount_shipping = false; // No incluir gastos de envio
// Opciones adicionales
$cartRule->active = 1;
$cartRule->highlight = 1; // Mostrar en checkout aunque no se aplique
$cartRule->partial_use = 0; // No generar vale con el resto
if ($cartRule->add()) {
return $cartRule;
}
return null;
}
// Uso en hookActionCustomerAccountAdd (registro de cliente)
public function hookActionCustomerAccountAdd($params)
{
$customer = $params['newCustomer'];
$coupon = createWelcomeCoupon((int) $customer->id);
if ($coupon) {
// Enviar email con el cupon
Mail::Send(
(int) $customer->id_lang,
'welcome_coupon', // Template en mails/
'Tu cupon de bienvenida',
[
'{coupon_code}' => $coupon->code,
'{coupon_value}' => '15%',
'{coupon_expires}' => $coupon->date_to,
'{firstname}' => $customer->firstname,
],
$customer->email,
$customer->firstname . ' ' . $customer->lastname,
null, null, null, null, _PS_MODULE_DIR_ . $this->name . '/mails/'
);
}
}
#Cupon de importe fijo
Cupon de 10 EUR de descuento
php
<?php
$cartRule = new CartRule();
$cartRule->code = 'DESCUENTO10-' . Tools::passwdGen(6);
foreach (Language::getLanguages(true) as $lang) {
$cartRule->name[$lang['id_lang']] = 'Descuento 10 EUR';
}
// Tipo: importe fijo
$cartRule->reduction_amount = 10.00;
$cartRule->reduction_tax = true; // Descuento sobre precio con impuestos
$cartRule->reduction_currency = (int) Configuration::get('PS_CURRENCY_DEFAULT');
// Sin producto especifico (aplica a todo el carrito)
$cartRule->reduction_product = 0;
$cartRule->date_from = date('Y-m-d H:i:s');
$cartRule->date_to = date('Y-m-d H:i:s', strtotime('+7 days'));
$cartRule->quantity = 100; // 100 usos totales
$cartRule->quantity_per_user = 1; // 1 uso por persona
$cartRule->active = 1;
$cartRule->add();
#Envio gratis automatico
Envio gratis sin codigo (automatico)
php
<?php
/**
* Regla de carrito sin codigo = se aplica automaticamente
* Perfecto para: envio gratis a partir de X EUR, promociones temporales
*/
$cartRule = new CartRule();
// SIN CODIGO → se aplica automaticamente cuando se cumplen las condiciones
$cartRule->code = '';
foreach (Language::getLanguages(true) as $lang) {
$cartRule->name[$lang['id_lang']] = 'Envio gratis pedidos +50 EUR';
}
// Tipo: envio gratis
$cartRule->free_shipping = true;
// Condicion: minimo 50 EUR en el carrito
$cartRule->minimum_amount = 50.00;
$cartRule->minimum_amount_tax = true;
$cartRule->minimum_amount_currency = (int) Configuration::get('PS_CURRENCY_DEFAULT');
// Valido indefinidamente
$cartRule->date_from = '2024-01-01 00:00:00';
$cartRule->date_to = '2030-12-31 23:59:59';
$cartRule->quantity = 0; // 0 = ilimitado
$cartRule->quantity_per_user = 0; // 0 = ilimitado
$cartRule->active = 1;
$cartRule->priority = 1; // Prioridad alta
$cartRule->add();
#Restricciones avanzadas
Restricciones por grupo, producto y categoria
php
<?php
// Despues de $cartRule->add(), puedes anadir restricciones:
// === Restringir a grupos de clientes ===
// Solo para grupo "VIP" (id_group = 4)
$cartRule->addRestriction(
CartRule::FILTER_GROUP,
[4] // IDs de grupos permitidos
);
// O manualmente:
Db::getInstance()->insert('cart_rule_group', [
'id_cart_rule' => (int) $cartRule->id,
'id_group' => 4,
]);
// === Restringir a productos especificos ===
// El cupon solo aplica si el carrito contiene estos productos
Db::getInstance()->insert('cart_rule_product_rule_group', [
'id_cart_rule' => (int) $cartRule->id,
'quantity' => 1, // Minimo 1 unidad del producto
]);
$idGroup = Db::getInstance()->Insert_ID();
Db::getInstance()->insert('cart_rule_product_rule', [
'id_product_rule_group' => $idGroup,
'type' => 'products', // 'products', 'categories', 'attributes', 'manufacturers'
]);
$idRule = Db::getInstance()->Insert_ID();
// Productos especificos
$productIds = [42, 55, 78];
foreach ($productIds as $idProduct) {
Db::getInstance()->insert('cart_rule_product_rule_value', [
'id_product_rule' => $idRule,
'id_item' => (int) $idProduct,
]);
}
// === Restringir a categorias ===
// Misma estructura pero con type = 'categories'
Db::getInstance()->insert('cart_rule_product_rule', [
'id_product_rule_group' => $idGroup,
'type' => 'categories',
]);
$idRule2 = Db::getInstance()->Insert_ID();
Db::getInstance()->insert('cart_rule_product_rule_value', [
'id_product_rule' => $idRule2,
'id_item' => 12, // id_category
]);
#Generar cupones masivamente
Generar 500 cupones unicos para campana de marketing
php
<?php
function generateCampaignCoupons(
string $prefix,
float $discount,
int $count,
string $expiresAt
): array {
$codes = [];
for ($i = 0; $i < $count; $i++) {
$cartRule = new CartRule();
$code = $prefix . '-' . strtoupper(Tools::passwdGen(8));
$cartRule->code = $code;
foreach (Language::getLanguages(true) as $lang) {
$cartRule->name[$lang['id_lang']] = "Campana {$prefix} #{$i}";
}
$cartRule->reduction_percent = $discount;
$cartRule->reduction_tax = true;
$cartRule->date_from = date('Y-m-d H:i:s');
$cartRule->date_to = $expiresAt;
$cartRule->quantity = 1;
$cartRule->quantity_per_user = 1;
$cartRule->active = 1;
if ($cartRule->add()) {
$codes[] = $code;
}
}
return $codes;
}
// Generar 500 cupones de 20% para Black Friday
$coupons = generateCampaignCoupons(
'BF2025',
20.0,
500,
'2025-12-01 23:59:59'
);
// $coupons = ['BF2025-A8K2M9X1', 'BF2025-P3Q7R4T6', ...]
#Aplicar cupon al carrito via codigo
Aplicar un cupon al carrito actual
php
<?php
/**
* Aplicar cupon programaticamente (por ejemplo, desde un hook)
*/
function applyCouponToCart(string $code, Context $context): array
{
$idCartRule = CartRule::getIdByCode($code);
if (!$idCartRule) {
return ['success' => false, 'error' => 'Codigo no valido'];
}
$cartRule = new CartRule($idCartRule);
// Verificar que se puede usar
$error = $cartRule->checkValidity(
$context,
false, // in_order_process
true, // display_error (devuelve mensaje)
true // already_in_cart check
);
if (is_string($error) && !empty($error)) {
return ['success' => false, 'error' => $error];
}
// Anadir al carrito
$context->cart->addCartRule((int) $cartRule->id);
return [
'success' => true,
'code' => $code,
'discount' => $cartRule->reduction_percent > 0
? $cartRule->reduction_percent . '%'
: Tools::displayPrice($cartRule->reduction_amount),
];
}
Descargar en Markdown
Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.