ldc-mesbr-app/app/Lib/Helpers/CouponHelper.php
Vincent BRIDIER b7cb4c0ab4
Merge API
2023-11-24 20:26:29 +01:00

718 lines
23 KiB
PHP

<?php
namespace App\Lib\Helpers;
use App\Enums\Country;
use App\Models\Campaign;
use App\Models\Coupon;
use App\Models\Customer;
use App\Models\PrintedWall;
use Carbon\Carbon;
use GdImage;
use Picqer\Barcode\BarcodeGeneratorPNG;
final class CouponHelper
{
/**
* fontArial path
*
* @var string
*/
private string $fontArial;
/**
* fontArialBd path
*
* @var string
*/
private string $fontArialBd;
/**
* fontImpact path
*
* @var string
*/
private string $fontImpact;
/**
* imgHand path
*
* @var string
*/
private string $imgHand;
/**
* imgMask path
*
* @var string
*/
private string $imgMask;
/**
* mask var
*
* @var \GdImage
*/
private GdImage $mask;
/**
* coupon resource
*
* @var \App\Models\Coupon
*/
private Coupon $coupon;
/**
* campaign resource
*
* @var \App\Models\Campaign
*/
private Campaign $campaign;
/**
* customer object
*
* @var object
*/
private object $customer;
/**
* printUniqId var
*
* @var string
*/
private string $printUniqId;
/**
* construct
*
* @param \App\Models\Coupon $coupon
* @param \App\Models\Campaign $campaign
* @param mixed $customer
* @param mixed $printUniqId
* @return void
* @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException.
*/
public function __construct(Coupon $coupon, Campaign $campaign, mixed $customer, mixed $printUniqId)
{
$this->fontArial = resource_path('br_generation/fonts/arial.ttf');
$this->fontArialBd = resource_path('br_generation/fonts/arialbd.ttf');
$this->fontImpact = resource_path('br_generation/fonts/impact.ttf');
$this->imgHand = resource_path('br_generation/images/hand.png');
$this->imgMask = resource_path('br_generation/images/mask.png');
// FIXME : Implementer gestion de cache pour ne pas regénérer ce qui est générique au coupon.
$this->mask = \imagecreatefrompng($this->imgMask);
$this->coupon = $coupon;
$this->campaign = $campaign;
$this->customer = $customer;
$this->printUniqId = $printUniqId;
}
/**
* Generate coupon picture and return base64
*
* @return string
* @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException.
* @throws \Psr\Container\NotFoundExceptionInterface NotFoundExceptionInterface.
* @throws \Psr\Container\ContainerExceptionInterface ContainerExceptionInterface.
*/
public function generate(): string
{
// Generic.
$this->addHand();
$this->addAmount();
$this->addWatermark();
$this->addValidOn();
$this->addDecoImg();
$this->addLogoImg();
// End Generic.
// User Specific.
$this->addLegalNotice();
$this->addCustomerInfos();
$this->addCustomerBarcode();
$this->addCouponBarcode();
// End User Specific.
// Date Specific.
$this->addValidityPeriod();
// End Date Specific.
ob_start();
imagejpeg($this->mask, null, 100);
$br = ob_get_contents();
ob_end_clean();
imagedestroy($this->mask);
return "data:image/jpeg;base64," . base64_encode($br);
}
/**
* Add coupom barcode into mask var
*
* used datas :
* - customer country
* - coupon gs1
* - coupon process_code
*
* @return void
* @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException.
*/
private function addCouponBarcode(): void
{
// Nom du centre de traitement.
if ($this->customer->country !== Country::france->value) {
$textReduc = "Traitement ScanCoupon/HighCo Data Benelux";
} else {
$textReduc = "• Traitement ScanCoupon •";
}
$ImageFond = imagecreate(270, 20);
imagecolorallocate($ImageFond, 255, 255, 255);
$black = imagecolorallocate($ImageFond, 0, 0, 0);
imagettftext($ImageFond, 9, 0, 0, 10, $black, $this->fontArialBd, $textReduc);
if ($this->customer->country !== 250) {
imagecopy($this->mask, $ImageFond, 60, 230, 0, 0, imagesx($ImageFond), imagesy($ImageFond));
} else {
imagecopy($this->mask, $ImageFond, 110, 322, 0, 0, imagesx($ImageFond), imagesy($ImageFond));
}
imagedestroy($ImageFond);
// Left barcode.
if ($this->customer->country !== 250) {
$codeBarre = imagecreatefromjpeg(storage_path($this->coupon->gs1));
imageresolution($codeBarre, 72);
list($width, $height) = getimagesize(storage_path($this->coupon->gs1));
$r = $width / $height;
$w = 285;
$h = 150;
if ($w / $h > $r) {
$newwidth = $h * $r;
$newheight = $h;
} else {
$newheight = $w / $r;
$newwidth = $w;
}
$test = imagecreatetruecolor($newwidth, $newheight);
imagecopyresampled($test, $codeBarre, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
imagecopy($this->mask, $test, 60, 250, 0, 0, imagesx($test), imagesy($test));
} else {
$codeBarre = $this->coupon->process_code;
$generator = new BarcodeGeneratorPNG();
$base64 = $generator->getBarcode($codeBarre, $generator::TYPE_CODE_128_A, 2, 46);
$barcodeImage = imagecreatefromstring($base64);
imagecopy($this->mask, $barcodeImage, 10, 342, 0, 0, imagesx($barcodeImage), imagesy($barcodeImage));
$ImageFond = imagecreate(380, 15);
imagecolorallocate($ImageFond, 255, 255, 255);
$black = imagecolorallocate($ImageFond, 0, 0, 0);
imagettftext($ImageFond, 11, 0, 0, 14, $black, $this->fontArial, $codeBarre);
imagecopy($this->mask, $ImageFond, 135, 390, 0, 0, imagesx($ImageFond), imagesy($ImageFond));
} //end if
imagedestroy($ImageFond);
// End left barcode.
}
/**
* Add customer barcode from printUniqId into mask var
*
* @return void
*/
private function addCustomerBarcode(): void
{
// Right barcode.
$barcode = str_pad($this->printUniqId, 13, "0", STR_PAD_LEFT);
$generator = new BarcodeGeneratorPNG();
$base64 = $generator->getBarcode($barcode, $generator::TYPE_CODE_128_A, 1, 46);
$barcodeImage = imagecreatefromstring($base64);
imagecopy($this->mask, $barcodeImage, 730, 342, 0, 0, imagesx($barcodeImage), imagesy($barcodeImage));
// Text.
$ImageFond = imagecreate(110, 15);
imagecolorallocate($ImageFond, 255, 255, 255);
$black = imagecolorallocate($ImageFond, 0, 0, 0);
imagettftext($ImageFond, 11, 0, 0, 14, $black, $this->fontArial, $barcode);
imagecopy($this->mask, $ImageFond, 800, 390, 0, 0, imagesx($ImageFond), imagesy($ImageFond));
// End text.
// End right barcode.
}
/**
* Add validity period from coupon validity_period into mask var
*
* @return void
* @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException.
* @throws \Psr\Container\NotFoundExceptionInterface NotFoundExceptionInterface.
* @throws \Psr\Container\ContainerExceptionInterface ContainerExceptionInterface.
*/
private function addValidityPeriod(): void
{
// Inscription de la date de validité.
$ImageFond = imagecreate(120, 40);
$white = imagecolorallocate($ImageFond, 255, 255, 255);
$black = imagecolorallocate($ImageFond, 0, 0, 0);
imagettftext($ImageFond, 8, 0, 1, 8, $black, $this->fontArialBd, sprintf("%s : ", trans("Valable jusqu'au")));
imagettftext(
$ImageFond,
8,
0,
20,
23,
$black,
$this->fontArial,
Carbon::now()->addDays($this->coupon->validity_period)->format("d/m/Y")
);
imagecolortransparent($ImageFond, $white);
imagecopy($this->mask, $ImageFond, 780, 142, 0, 0, imagesx($ImageFond), imagesy($ImageFond));
imagedestroy($ImageFond);
}
/**
* Add customer infos into mask var
*
* used datas :
* - customer firstname
* - customer lastname
* - customer address
* - customer postcode
* - customer city
* - printUniqId
*
* @return void
*/
private function addCustomerInfos(): void
{
$libelle = "OFFRE RÉSERVÉE À";
$user = sprintf(
"%s %s\r\n%s\r\n%s\r\n%s\r\nid %s",
$this->customer->firstname,
$this->customer->lastname,
$this->customer->address,
$this->customer->postcode,
$this->customer->city,
str_pad($this->printUniqId, 13, "0", STR_PAD_LEFT)
);
$ImageFond = imagecreate(120, 80);
$white = imagecolorallocate($ImageFond, 255, 255, 255);
$black = imagecolorallocate($ImageFond, 0, 0, 0);
$box1 = imagettfbbox(8, 0, $this->fontArial, $user);
$box2 = imagettfbbox(8, 0, $this->fontArial, $libelle);
imagettftext(
$ImageFond,
8,
0,
(120 / 2) - (abs($box2[4]) - abs($box2[6])) / 2,
10,
$black,
$this->fontArialBd,
$libelle
);
imagettftext(
$ImageFond,
8,
0,
(120 / 2) - (abs($box1[4]) - abs($box1[6])) / 2,
25,
$black,
$this->fontArial,
$user
);
imagecolortransparent($ImageFond, $white);
imagecopy($this->mask, $ImageFond, 770, 40, 0, 0, imagesx($ImageFond), imagesy($ImageFond));
imagedestroy($ImageFond);
}
/**
* Add logo picture from brand logo into mask var
*
* @return void
* @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException.
*/
private function addLogoImg(): void
{
// ---- Copie le logo dans le mask
$logo = imagecreatefromjpeg(storage_path($this->campaign->brand->logo));
imagealphablending($this->mask, true);
imagesavealpha($this->mask, true);
imagecopy($this->mask, $logo, 767, 220, 0, 0, imagesx($logo), imagesy($logo));
imagedestroy($logo);
imagedestroy($logo);
}
/**
* add decoration picture from coupon decoration into mask var
*
* @return void
* @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException.
*/
private function addDecoImg(): void
{
// Copie l'image de decoration dans le mask.
$pdt = imagecreatefromjpeg(storage_path($this->coupon->decoration));
imagealphablending($this->mask, true);
imagesavealpha($this->mask, true);
imagecopy($this->mask, $pdt, 40, 10, 0, 0, imagesx($pdt), imagesy($pdt));
imagedestroy($pdt);
}
/**
* Add valid on legal text from coupon valid_on into mask var
*
* @return void
*/
private function addValidOn(): void
{
$maxCharByLines = 64;
$ImageFond = imagecreate(387, 200);
$white = imagecolorallocate($ImageFond, 255, 255, 255);
$black = imagecolorallocate($ImageFond, 0, 0, 0);
$textReducs = explode("\r\n", str_replace("<br>", "\r\n", $this->coupon->valid_on));
$y = 14;
foreach ($textReducs as $line) {
foreach (str_split($line, $maxCharByLines) as $sLine) {
$this->imagettftextSp($ImageFond, 10, 0, 0, $y, $black, $this->fontArialBd, $sLine, 0.01);
$y += 12;
}
}
imagecolortransparent($ImageFond, $white);
imagecopy($this->mask, $ImageFond, 360, 170, 0, 0, imagesx($ImageFond), imagesy($ImageFond));
imagedestroy($ImageFond);
}
/**
* Add watermark into mask var
*
* used datas :
* - brand name
* - coupon amount
*
* @return void
*/
private function addWatermark(): void
{
// Inscription filigrane.
$watermark = sprintf(
"%s %s €",
strtoupper($this->campaign->brand->name),
number_format($this->coupon->amount, 2, ",", " ")
);
$line_filigramme = "";
$textFili = "";
for ($i = 0; $i < 11; $i++) {
$line_filigramme .= $watermark . " ";
}
$line_filigramme .= "\r\n";
for ($i = 0; $i < 30; $i++) {
$textFili .= $line_filigramme;
}
$textFiliLines = explode("\r\n", $textFili);
$ImageFond = imagecreate(402, 240);
$white = imagecolorallocate($ImageFond, 255, 255, 255);
$black = imagecolorallocate($ImageFond, 0, 0, 0);
$y = 0;
foreach ($textFiliLines as $textFiliLine) {
$y += 20;
$this->imagettftextSp($ImageFond, 11, 25, -100, $y, $black, $this->fontArial, $textFiliLine, 0.01);
}
imagecolortransparent($ImageFond, $white);
imagecopymerge($this->mask, $ImageFond, 349, 1, 0, 0, imagesx($ImageFond), imagesy($ImageFond), 30);
imagedestroy($ImageFond);
}
/**
* Add amount from coupon amount into mask var
*
* @return void
*/
private function addAmount(): void
{
// ---- Inscription du montant du BR
$textMontant = number_format($this->coupon->amount, 2, ",", " ");
$textEuro = "€";
$libReduc = "DE RÉDUCTION IMMÉDIATE";
$ImageFond = imagecreate(265, 200);
$white = imagecolorallocate($ImageFond, 255, 255, 255);
$blue = imagecolorallocate($ImageFond, 8, 169, 223);
$grey = imagecolorallocate($ImageFond, 219, 219, 221);
$this->imagettftextContour(
$ImageFond,
95,
0,
5,
110,
$grey,
$this->fontImpact,
$textMontant,
$blue,
3,
3,
3,
3
);
$this->imagettftextContour($ImageFond, 50, 0, 220, 55, $grey, $this->fontArial, $textEuro, $blue, 2, 2, 2, 2);
$this->imagettftextContour($ImageFond, 16, 0, 0, 150, $grey, $this->fontImpact, $libReduc, $blue, 1, 1, 1, 1);
imagecolortransparent($ImageFond, $white);
imagecopy($this->mask, $ImageFond, 360, 10, 0, 0, imagesx($ImageFond), imagesy($ImageFond));
imagedestroy($ImageFond);
}
/**
* Add hand into mask var
*
* @return void
*/
private function addHand(): void
{
// Copie la main dans le mask.
$hand = imagecreatefrompng($this->imgHand);
imagecopy($this->mask, $hand, 577, 2, 0, 0, imagesx($hand), imagesy($hand));
imagealphablending($this->mask, false);
imagesavealpha($this->mask, true);
imagedestroy($hand);
}
/**
* Add legal notice into mask var using writeLegalNotice method, taking account multiple factors
*
* used datas :
* - coupon legal_notices
* - customer country
* - brand rcs
* - brand contact_mail
*
* @return void
* @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException.
* @throws \Psr\Container\NotFoundExceptionInterface NotFoundExceptionInterface.
* @throws \Psr\Container\ContainerExceptionInterface ContainerExceptionInterface.
*/
private function addLegalNotice(): void
{
// Si on trouve la pseudo balise <nl> alors on a les mentions internationales.
if (strpos($this->coupon->legal_notices, "<nl>")) {
$legalNotices = explode('<nl>', $this->coupon->legal_notices);
// Si le customer ne viens pas de France.
if ($this->customer->country !== Country::france->value) {
$this->writeLegalNotice(sprintf(
"%s\r\n%s\r\n%s",
$legalNotices[0],
$legalNotices[1],
$this->campaign->brand->rcs
), $this->campaign->brand->contact_mail);
} else {
$this->writeLegalNotice(sprintf(
"%s\r\n%s",
$legalNotices[0],
$this->campaign->brand->rcs
), $this->campaign->brand->contact_mail);
}
} else {
// Si on ne trouve pas la pseudo balise <nl> alors on a que du FR.
$this->writeLegalNotice(sprintf(
"%s\r\n%s",
$this->coupon->legal_notices,
$this->campaign->brand->rcs
), $this->campaign->brand->contact_mail);
} //end if
}
/**
* Write legal notice into mask var
*
* @param string $legalNotice
* @param string $contactMail
* @return void
* @throws \Illuminate\Contracts\Container\BindingResolutionException. BindingResolutionException.
* @throws \Psr\Container\NotFoundExceptionInterface NotFoundExceptionInterface.
* @throws \Psr\Container\ContainerExceptionInterface ContainerExceptionInterface.
*/
private function writeLegalNotice(string $legalNotice, string $contactMail): void
{
$maxCharByLines = 103;
$ImageMentionFond = imagecreate(420, 145);
$white = imagecolorallocate($ImageMentionFond, 255, 255, 255);
imagefilledrectangle($ImageMentionFond, 0, 0, 414, 99, $white);
$black = imagecolorallocate($ImageMentionFond, 0, 0, 0);
$lines_mentions = explode("\r\n", $legalNotice);
$y = 19;
foreach ($lines_mentions as $line) {
foreach (str_split($line, $maxCharByLines) as $sLine) {
$this->imagettftextSp($ImageMentionFond, 7, 0, 15, $y, $black, $this->fontArial, $sLine, 0.01);
$y += 9;
}
}
$this->imagettftextSp(
$ImageMentionFond,
7,
0,
15,
$y,
$black,
$this->fontArialBd,
sprintf("%s : %s", trans('Renseignements'), $contactMail),
0.01
);
imagecopy(
$this->mask,
$ImageMentionFond,
335,
235,
0,
0,
imagesx($ImageMentionFond),
imagesy($ImageMentionFond)
);
imagedestroy($ImageMentionFond);
}
/**
* Create picture from text Contour
*
* @todo Définir le sens de contour
* @todo remettre au propre les types du proto
*
* @param mixed $image
* @param mixed $fontsize
* @param mixed $angle
* @param mixed $x
* @param mixed $y
* @param mixed $color
* @param mixed $font
* @param mixed $text
* @param mixed $color_contour
* @param integer $contour_haut
* @param integer $contour_bas
* @param integer $contour_gauche
* @param integer $contour_droite
* @return void
*/
private function imagettftextContour(
mixed $image,
mixed $fontsize,
mixed $angle,
mixed $x,
mixed $y,
mixed $color,
mixed $font,
mixed $text,
mixed $color_contour,
int $contour_haut = 1,
int $contour_bas = 1,
int $contour_gauche = 1,
int $contour_droite = 1
): void {
$coords_x = [];
$coords_y = [];
for ($i_y = -$contour_haut; $i_y <= $contour_bas; $i_y++) {
$y_temp = array_fill(0, $contour_gauche + $contour_droite + 1, $i_y);
$x_temp = [];
for ($i_x = -$contour_gauche; $i_x <= $contour_droite; $i_x++) {
$x_temp[] = $i_x;
}
$coords_x = array_merge($coords_x, $x_temp);
$coords_y = array_merge($coords_y, $y_temp);
}
$c = count($coords_x);
for ($i = 0; $i < $c; $i++) {
imagettftext(
$image,
$fontsize,
$angle,
$x + $coords_x[$i],
$y + $coords_y[$i],
$color_contour,
$font,
$text
);
}
imagettftext($image, $fontsize, $angle, $x, $y, $color, $font, $text);
}
/**
* Create picture from text Sp
*
* @todo définir Sp
* @todo remettre au propre les types du proto
*
* @param mixed $image
* @param mixed $size
* @param mixed $angle
* @param mixed $x
* @param mixed $y
* @param mixed $color
* @param mixed $font
* @param mixed $text
* @param integer $spacing
* @return void
*/
private function imagettftextSp(
mixed $image,
mixed $size,
mixed $angle,
mixed $x,
mixed $y,
mixed $color,
mixed $font,
mixed $text,
int $spacing = 0
): void {
if ($spacing == 0) {
imagefttext($image, $size, $angle, $x, $y, $color, $font, $text);
} else {
$temp_x = $x;
$temp_y = $y;
// To avoid special char problems.
$char_array = preg_split('//u', $text, -1, PREG_SPLIT_NO_EMPTY);
foreach ($char_array as $char) {
imagefttext($image, $size, $angle, $temp_x, $temp_y, $color, $font, $char);
$bbox = imagettfbbox($size, 0, $font, $char);
$temp_x += cos(deg2rad($angle)) * ($spacing + ($bbox[2] - $bbox[0]));
$temp_y -= sin(deg2rad($angle)) * ($spacing + ($bbox[2] - $bbox[0]));
}
}
}
/**
* Check if a coupon attached to a wall campaign is used
*
* @param \App\Models\Coupon $coupon
* @param \App\Models\Campaign $campaign
* @param \App\Models\Customer $customer
* @return boolean
*/
public static function wallCouponIsUsed(Coupon $coupon, Campaign $campaign, Customer $customer): bool
{
// FIXME : Revoir la règle de gestion et donc l'implémentation.
$isUsed = false;
// ---- Contrôle le nombre limite d'impression
if ($coupon->limit_qty > 0) {
$count = PrintedWall::where(
[
['campaign_id', '=', $campaign->id],
['coupon_id', '=', $coupon->id],
['customer_id', '=', $customer->id]
]
)->count();
if ($count >= $coupon->limit_qty) {
$isUsed = true;
}
}
// ---- Contrôle la limite de période de diffusion
if ($coupon->limit_period > 0) {
$count = PrintedWall::where(
[
['campaign_id', '=', $campaign->id],
['coupon_id', '=', $coupon->id],
['customer_id', '=', $customer->id]
]
)->orderBy('created_at', 'DESC')->first();
if ($count && $count->count() > 0) {
if ((new Carbon($count->created_at))->addDays($coupon->limit_period)->greaterThan(Carbon::now())) {
$isUsed = true;
}
}
}
return $isUsed;
}
}