reportedCompany($hash); App::setLocale(CompanySetting::getSetting('language', $company->id)); $window = $request->only(['from_date', 'to_date']); $items = InvoiceItem::query() ->whereCompany($company->id) ->applyInvoiceFilters($window) ->itemAttributes() ->get(); view()->share([ 'items' => $items, 'totalAmount' => $items->sum('total_amount'), ] + $this->pageChrome($request, $company)); return $this->emit($request, 'sales-items'); } /** * The company named by the hash, once the caller has been let through. * * Nothing upstream tells Bouncer which company to weigh abilities against: * these links carry no company header, and the report ability is stored * per company, so the unscoped check matched nothing and every report * answered 403. Pointing the scope at the company in the URL settles that * without widening access, because the policy still asks for membership. * The hash is an address, not a credential. * * @param string $hash */ private function reportedCompany($hash): Company { $company = Company::query()->where('unique_hash', $hash)->firstOrFail(); BouncerFacade::scope()->to($company->id); $this->authorize('view report', $company); return $company; } /** * What every report prints around its figures: the company and its logo, * the window in the company's own date format, and the currency the * amounts are stated in. * * @return array */ private function pageChrome(Request $request, Company $company): array { $pattern = CompanySetting::getSetting('carbon_date_format', $company->id); $opened = Carbon::createFromFormat('Y-m-d', $request->from_date)->translatedFormat($pattern); $closed = Carbon::createFromFormat('Y-m-d', $request->to_date)->translatedFormat($pattern); $currencyId = CompanySetting::getSetting('currency', $company->id); $currency = Currency::findOrFail($currencyId); return [ 'company' => $company, 'logo' => $company->logo_path, 'from_date' => $opened, 'to_date' => $closed, 'currency' => $currency, ]; } /** * Hand the rendered report over in whichever of the three shapes the query * string asks for. * * Reports have no template chooser, so an override is a file of the same * name dropped into storage/app/templates/pdf/reports/, which the resolver * prefers over the built-in one. * * The document is built before the preview branch is taken and not after: * a preview costs a full render it never uses, which is wasteful but is * also what the templates have always been exercised through. */ private function emit(Request $request, string $design) { $design = PdfTemplateUtils::resolveView('reports', $design); $document = Pdf::loadView($design, [], PdfPageSetup::forReports()); if ($request->exists('preview')) { return view($design); } return $request->exists('download') ? $document->download() : $document->stream(); } }