Skip to content

Commit 357e85d

Browse files
committed
Merge remote-tracking branch 'origin/develop'
2 parents 75cfcb8 + 9da9166 commit 357e85d

File tree

6 files changed

+179
-167
lines changed

6 files changed

+179
-167
lines changed

app/Http/Controllers/Account/AcceptanceController.php

Lines changed: 50 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,6 @@
1313
use App\Models\Contracts\Acceptable;
1414
use App\Models\Setting;
1515
use App\Models\User;
16-
use App\Models\AssetModel;
17-
use App\Models\Accessory;
18-
use App\Models\License;
19-
use App\Models\Component;
20-
use App\Models\Consumable;
2116
use App\Notifications\AcceptanceAssetAcceptedNotification;
2217
use App\Notifications\AcceptanceAssetAcceptedToUserNotification;
2318
use App\Notifications\AcceptanceAssetDeclinedNotification;
@@ -26,12 +21,9 @@
2621
use Illuminate\Support\Facades\Mail;
2722
use Illuminate\Support\Facades\Storage;
2823
use Illuminate\Support\Str;
29-
use App\Http\Controllers\SettingsController;
30-
use Carbon\Carbon;
3124
use \Illuminate\Contracts\View\View;
3225
use \Illuminate\Http\RedirectResponse;
3326
use Illuminate\Support\Facades\Log;
34-
use TCPDF;
3527
use App\Helpers\Helper;
3628

3729
class AcceptanceController extends Controller
@@ -83,6 +75,11 @@ public function create($id) : View | RedirectResponse
8375
public function store(Request $request, $id) : RedirectResponse
8476
{
8577
$acceptance = CheckoutAcceptance::find($id);
78+
$assigned_user = User::find($acceptance->assigned_to_id);
79+
$settings = Setting::getSettings();
80+
$path_logo = '';
81+
$sig_filename='';
82+
8683

8784
if (is_null($acceptance)) {
8885
return redirect()->route('account.accept')->with('error', trans('admin/hardware/message.does_not_exist'));
@@ -118,135 +115,62 @@ public function store(Request $request, $id) : RedirectResponse
118115
Storage::makeDirectory('private_uploads/eula-pdfs', 775);
119116
}
120117

121-
122118
$item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id);
123-
$checkout_type_shortname = strtolower(str_replace('App\Models\\', '', $acceptance->checkoutable_type));
124-
$pdf_filename = 'accepted-'.$acceptance->checkoutable_id.'-'.$checkout_type_shortname.'-eula-'.date('Y-m-d-h-i-s').'.pdf';
125-
$sig_filename='';
126-
127-
if ($request->input('asset_acceptance') == 'accepted') {
128-
129-
if (Setting::getSettings()->require_accept_signature == '1') {
130-
131-
// The item was accepted, check for a signature
132-
if ($request->filled('signature_output')) {
133-
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
134-
$data_uri = $request->input('signature_output');
135-
$encoded_image = explode(',', $data_uri);
136-
$decoded_image = base64_decode($encoded_image[1]);
137-
Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image);
138119

139-
// No image data is present, kick them back.
140-
// This mostly only applies to users on super-duper crapola browsers *cough* IE *cough*
141-
} else {
142-
return redirect()->back()->with('error', trans('general.shitty_browser'));
143-
}
144-
}
145120

146-
$assigned_user = User::find($acceptance->assigned_to_id);
147121

122+
// If signatures are required, make sure we have one
123+
if (Setting::getSettings()->require_accept_signature == '1') {
148124

149-
/**
150-
* Gather the data for the PDF. We fire this whether there is a signature required or not,
151-
* since we want the moment-in-time proof of what the EULA was when they accepted it.
152-
*/
153-
$branding_settings = SettingsController::getPDFBranding();
125+
// The item was accepted, check for a signature
126+
if ($request->filled('signature_output')) {
127+
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
128+
$data_uri = $request->input('signature_output');
129+
$encoded_image = explode(',', $data_uri);
130+
$decoded_image = base64_decode($encoded_image[1]);
131+
Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image);
154132

155-
$path_logo = "";
156-
157-
// Check for the PDF logo path and use that, otherwise use the regular logo path
158-
if (!is_null($branding_settings->acceptance_pdf_logo)) {
159-
$path_logo = public_path() . '/uploads/' . $branding_settings->acceptance_pdf_logo;
160-
} elseif (!is_null($branding_settings->logo)) {
161-
$path_logo = public_path() . '/uploads/' . $branding_settings->logo;
162-
}
163-
164-
$data = [
165-
'item_tag' => $item->asset_tag,
166-
'item_model' => $item->model ? $item->model->name : $item->display_name,
167-
'item_serial' => $item->serial,
168-
'item_status' => $item->assetstatus?->name,
169-
'eula' => $item->getEula(),
170-
'note' => $request->input('note'),
171-
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d H:i:s'),
172-
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d H:i:s'),
173-
'assigned_to' => $assigned_user->display_name,
174-
'company_name' => $branding_settings->site_name,
175-
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
176-
'logo' => $path_logo,
177-
'date_settings' => $branding_settings->date_display_format,
178-
'admin' => auth()->user()->present()?->fullName,
179-
'qty' => $acceptance->qty ?? 1,
180-
];
181-
182-
// set some language dependent data:
183-
$lg = Array();
184-
$lg['a_meta_charset'] = 'UTF-8';
185-
$lg['w_page'] = 'page';
186-
187-
$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);
188-
$pdf->setRTL(false);
189-
$pdf->setLanguageArray($lg);
190-
$pdf->SetFontSubsetting(true);
191-
$pdf->SetCreator('Snipe-IT');
192-
$pdf->SetAuthor($data['assigned_to']);
193-
$pdf->SetTitle('Asset Acceptance: '.$data['item_tag']);
194-
$pdf->SetSubject('Asset Acceptance: '.$data['item_tag']);
195-
$pdf->SetKeywords('Snipe-IT, assets, acceptance, eula', 'tos');
196-
$pdf->SetFont('dejavusans', '', 8, '', true);
197-
$pdf->SetPrintHeader(false);
198-
$pdf->SetPrintFooter(false);
199-
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
200-
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
201-
202-
$pdf->AddPage();
203-
$pdf->writeHTML('<img src="'.$path_logo.'" height="30">', true, 0, true, 0, '');
204-
205-
if ($data['item_tag']) {
206-
$pdf->writeHTML("<strong>" . trans('general.asset_tag') . '</strong>: ' . $data['item_tag'], true, 0, true, 0, '');
133+
// No image data is present, kick them back.
134+
// This mostly only applies to users on super-duper crapola browsers *cough* IE *cough*
135+
} else {
136+
return redirect()->back()->with('error', trans('general.shitty_browser'));
207137
}
208-
$pdf->writeHTML("<strong>".trans('general.asset_model').'</strong>: '.$data['item_model'], true, 0, true, 0, '');
209-
if ($data['item_serial']) {
210-
$pdf->writeHTML("<strong>".trans('admin/hardware/form.serial').'</strong>: '.$data['item_serial'], true, 0, true, 0, '');
211-
}
212-
$pdf->writeHTML("<strong>".trans('general.assigned_date').'</strong>: '.$data['check_out_date'], true, 0, true, 0, '');
213-
$pdf->writeHTML("<strong>".trans('general.assignee').'</strong>: '.$data['assigned_to'], true, 0, true, 0, '');
214-
$pdf->Ln();
138+
}
215139

216-
// Break the EULA into lines based on newlines, and check each line for RTL or CJK characters
217-
$eula_lines = preg_split("/\r\n|\n|\r/", $item->getEula());
218140

219-
foreach ($eula_lines as $eula_line) {
220-
Helper::hasRtl($eula_line) ? $pdf->setRTL(true) : $pdf->setRTL(false);
221-
Helper::isCjk($eula_line) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
141+
// Get the data array ready for the notifications and PDF generation
142+
$data = [
143+
'item_tag' => $item->asset_tag,
144+
'item_name' => $item->name, // this handles licenses seats, which don't have a 'name' field
145+
'item_model' => $item->model?->name,
146+
'item_serial' => $item->serial,
147+
'item_status' => $item->assetstatus?->name,
148+
'eula' => $item->getEula(),
149+
'note' => $request->input('note'),
150+
'check_out_date' => Helper::getFormattedDateObject($acceptance->created_at, 'datetime', false),
151+
'accepted_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false),
152+
'declined_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false),
153+
'assigned_to' => $assigned_user->display_name,
154+
'site_name' => $settings->site_name,
155+
'company_name' => $item->company?->name?? $settings->site_name,
156+
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
157+
'logo' => ($settings->acceptance_pdf_logo) ? public_path() . '/uploads/' . $settings->acceptance_pdf_logo : null,
158+
'date_settings' => $settings->date_display_format,
159+
'admin' => auth()->user()->present()?->fullName,
160+
'qty' => $acceptance->qty ?? 1,
161+
];
222162

223-
$pdf->writeHTML(Helper::parseEscapedMarkedown($eula_line), true, 0, true, 0, '');
224-
}
225-
$pdf->Ln();
226-
$pdf->Ln();
227-
$pdf->setRTL(false);
228-
$pdf->writeHTML('<br><br>', true, 0, true, 0, '');
229-
230-
if ($data['note'] != null) {
231-
Helper::isCjk($data['note']) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
232-
$pdf->writeHTML("<strong>".trans('general.notes') . '</strong>: ' . $data['note'], true, 0, true, 0, '');
233-
$pdf->Ln();
234-
}
235163

236-
if ($data['signature'] != null) {
237-
238-
$pdf->writeHTML('<img src="'.$data['signature'].'" style="max-width: 600px;">', true, 0, true, 0, '');
239-
$pdf->writeHTML('<hr>', true, 0, true, 0, '');
240-
}
241-
242-
$pdf->writeHTML("<strong>".trans('general.accepted_date').'</strong>: '.$data['accepted_date'], true, 0, true, 0, '');
164+
if ($request->input('asset_acceptance') == 'accepted') {
243165

244166

245-
$pdf_content = $pdf->Output($pdf_filename, 'S');
167+
$pdf_filename = 'accepted-'.$acceptance->checkoutable_id.'-'.$acceptance->display_checkoutable_type.'-eula-'.date('Y-m-d-h-i-s').'.pdf';
246168

169+
// Generate the PDF content
170+
$pdf_content = $acceptance->generateAcceptancePdf($data, $acceptance);
247171
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf_content);
248172

249-
173+
// Log the acceptance
250174
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
251175

252176
// Send the PDF to the signing user
@@ -269,45 +193,9 @@ public function store(Request $request, $id) : RedirectResponse
269193

270194
$return_msg = trans('admin/users/message.accepted');
271195

272-
// Item was not accepted
196+
// Item was declined
273197
} else {
274198

275-
if (Setting::getSettings()->require_accept_signature == '1') {
276-
277-
// The item was declined, check for a signature
278-
if ($request->filled('signature_output')) {
279-
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
280-
$data_uri = $request->input('signature_output');
281-
$encoded_image = explode(',', $data_uri);
282-
$decoded_image = base64_decode($encoded_image[1]);
283-
Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image);
284-
285-
// No image data is present, kick them back.
286-
// This mostly only applies to users on super-duper crapola browsers *cough* IE *cough*
287-
} else {
288-
return redirect()->back()->with('error', trans('general.shitty_browser'));
289-
}
290-
}
291-
292-
// Format the data to send the declined notification
293-
$branding_settings = SettingsController::getPDFBranding();
294-
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
295-
296-
$data = [
297-
'item_tag' => $item->asset_tag,
298-
'item_model' => $item->model ? $item->model->name : $item->display_name,
299-
'item_serial' => $item->serial,
300-
'item_status' => $item->assetstatus?->name,
301-
'note' => $request->input('note'),
302-
'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'),
303-
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
304-
'assigned_to' => $assigned_to,
305-
'company_name' => $branding_settings->site_name,
306-
'date_settings' => $branding_settings->date_display_format,
307-
'qty' => $acceptance->qty ?? 1,
308-
];
309-
310-
311199
for ($i = 0; $i < ($acceptance->qty ?? 1); $i++) {
312200
$acceptance->decline($sig_filename, $request->input('note'));
313201
}
@@ -318,6 +206,8 @@ public function store(Request $request, $id) : RedirectResponse
318206
$return_msg = trans('admin/users/message.declined');
319207
}
320208

209+
210+
// Send an email notification if one is requested
321211
if ($acceptance->alert_on_response_id) {
322212
try {
323213
$recipient = User::find($acceptance->alert_on_response_id);
@@ -336,9 +226,10 @@ public function store(Request $request, $id) : RedirectResponse
336226
Log::warning($e);
337227
}
338228
}
339-
340229
return redirect()->to('account/accept')->with('success', $return_msg);
341230

342231
}
343232

233+
234+
344235
}

app/Models/CheckoutAcceptance.php

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
namespace App\Models;
44

5+
use App\Helpers\Helper;
56
use Illuminate\Database\Eloquent\Builder;
7+
use Illuminate\Database\Eloquent\Casts\Attribute;
68
use Illuminate\Database\Eloquent\Factories\HasFactory;
79
use Illuminate\Database\Eloquent\Model;
810
use Illuminate\Database\Eloquent\SoftDeletes;
911
use Illuminate\Notifications\Notifiable;
12+
use TCPDF;
1013

1114
class CheckoutAcceptance extends Model
1215
{
@@ -153,4 +156,94 @@ public function scopeDeclined(Builder $query)
153156
{
154157
return $query->whereNull('accepted_at')->whereNotNull('declined_at');
155158
}
159+
160+
protected function displayCheckoutableType(): Attribute
161+
{
162+
return Attribute:: make(
163+
get: fn(mixed $value) => strtolower(str_replace('App\Models\\', '', $this->checkoutable_type)),
164+
);
165+
}
166+
167+
public function generateAcceptancePdf($data, $pdf_filename) {
168+
169+
// set some language dependent data:
170+
$lg = Array();
171+
$lg['a_meta_charset'] = 'UTF-8';
172+
$lg['w_page'] = 'page';
173+
174+
$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);
175+
$pdf->setRTL(false);
176+
$pdf->setLanguageArray($lg);
177+
$pdf->SetFontSubsetting(true);
178+
$pdf->SetCreator('Snipe-IT Asset Management System');
179+
$pdf->SetAuthor($data['assigned_to']);
180+
$pdf->SetTitle('Asset Acceptance: '.$data['item_tag']);
181+
$pdf->SetSubject('Asset Acceptance: '.$data['item_tag']);
182+
$pdf->SetKeywords('Snipe-IT, assets, acceptance, eula, tos');
183+
$pdf->SetFont('dejavusans', '', 8, '', true);
184+
$pdf->SetPrintHeader(false);
185+
$pdf->SetPrintFooter(false);
186+
187+
$pdf->AddPage();
188+
if ($data['logo'] != null) {
189+
$pdf->writeHTML('<img src="'.$data['logo'].'">', true, 0, true, 0, '');
190+
} else {
191+
$pdf->writeHTML('<h3>'.$data['site_name'].'</h3><br /><br />', true, 0, true, 0, 'C');
192+
}
193+
194+
$pdf->Ln();
195+
$pdf->writeHTML(trans('general.date') . ': ' . Helper::getFormattedDateObject(now(), 'datetime', false), true, 0, true, 0, '');
196+
197+
if ($data['company_name'] != null) {
198+
$pdf->writeHTML(trans('general.company') . ': ' . e($data['company_name']), true, 0, true, 0, '');
199+
}
200+
if ($data['item_tag'] != null) {
201+
$pdf->writeHTML(trans('general.asset_tag') . ': ' . e($data['item_tag']), true, 0, true, 0, '');
202+
}
203+
if ($data['item_name'] != null) {
204+
$pdf->writeHTML(trans('general.name') . ': ' . e($data['item_name']), true, 0, true, 0, '');
205+
}
206+
if ($data['item_model'] != null) {
207+
$pdf->writeHTML(trans('general.asset_model') . ': ' . e($data['item_model']), true, 0, true, 0, '');
208+
}
209+
if ($data['item_serial'] != null) {
210+
$pdf->writeHTML(trans('admin/hardware/form.serial').': '.e($data['item_serial']), true, 0, true, 0, '');
211+
}
212+
$pdf->Ln();
213+
$pdf->writeHTML('<hr>', true, 0, true, 0, '');
214+
215+
216+
// Break the EULA into lines based on newlines, and check each line for RTL or CJK characters
217+
$eula_lines = preg_split("/\r\n|\n|\r/", $data['eula']);
218+
219+
foreach ($eula_lines as $eula_line) {
220+
Helper::hasRtl($eula_line) ? $pdf->setRTL(true) : $pdf->setRTL(false);
221+
Helper::isCjk($eula_line) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
222+
223+
$pdf->writeHTML(Helper::parseEscapedMarkedown($eula_line), true, 0, true, 0, '');
224+
}
225+
$pdf->Ln();
226+
$pdf->Ln();
227+
$pdf->setRTL(false);
228+
$pdf->Ln();
229+
230+
if ($data['signature'] != null) {
231+
$pdf->writeHTML('<img src="'.$data['signature'].'" style="max-width: 600px;">', true, 0, true, 0, '');
232+
$pdf->writeHTML('<hr>', true, 0, true, 0, '');
233+
}
234+
235+
if ($data['note'] != null) {
236+
Helper::isCjk($data['note']) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
237+
$pdf->writeHTML(trans('general.notes') . ': ' . e($data['note']), true, 0, true, 0, '');
238+
$pdf->Ln();
239+
}
240+
241+
$pdf->writeHTML(trans('general.assignee').': '.e($data['assigned_to']), true, 0, true, 0, '');
242+
$pdf->writeHTML(trans('general.assigned_date').': '.e($data['check_out_date']), true, 0, true, 0, '');
243+
$pdf->writeHTML(trans('general.accepted_date').': '.e($data['accepted_date']), true, 0, true, 0, '');
244+
245+
return $pdf->Output($pdf_filename, 'S');
246+
247+
248+
}
156249
}

0 commit comments

Comments
 (0)