Lint PHP code psr-12, add GH action
This commit is contained in:
@@ -3,9 +3,9 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Forms\FormStatistic;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\Forms\FormView;
|
||||
use App\Models\Forms\FormSubmission;
|
||||
use App\Models\Forms\FormView;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class CleanDatabase extends Command
|
||||
@@ -51,13 +51,13 @@ class CleanDatabase extends Command
|
||||
->orderBy('date')
|
||||
->groupBy('form_id', 'date')
|
||||
->get()->each(function ($row) use (&$finalData) {
|
||||
$finalData[$row->form_id."-".$row->date] = [
|
||||
$finalData[$row->form_id.'-'.$row->date] = [
|
||||
'form_id' => $row->form_id,
|
||||
'date' => $row->date,
|
||||
'data' => [
|
||||
'views' => $row->views,
|
||||
'submissions' => 0
|
||||
]
|
||||
'submissions' => 0,
|
||||
],
|
||||
];
|
||||
});
|
||||
|
||||
@@ -68,7 +68,7 @@ class CleanDatabase extends Command
|
||||
->orderBy('date')
|
||||
->groupBy('form_id', 'date')
|
||||
->get()->each(function ($row) use (&$finalData) {
|
||||
$key = $row->form_id."-".$row->date;
|
||||
$key = $row->form_id.'-'.$row->date;
|
||||
if (isset($finalData[$key])) {
|
||||
$finalData[$key]['data']['submissions'] = $row->submissions;
|
||||
} else {
|
||||
@@ -77,8 +77,8 @@ class CleanDatabase extends Command
|
||||
'date' => $row->date,
|
||||
'data' => [
|
||||
'views' => 0,
|
||||
'submissions' => $row->submissions
|
||||
]
|
||||
'submissions' => $row->submissions,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ class GenerateTemplate extends Command
|
||||
*/
|
||||
protected $description = 'Generates a new form template from a prompt';
|
||||
|
||||
const MAX_RELATED_TEMPLATES = 8;
|
||||
public const MAX_RELATED_TEMPLATES = 8;
|
||||
|
||||
const FORM_STRUCTURE_PROMPT = <<<EOD
|
||||
public const FORM_STRUCTURE_PROMPT = <<<'EOD'
|
||||
You are an AI assistant for OpnForm, a form builder and your job is to build a form for our user.
|
||||
|
||||
Forms are represented as Json objects. Here's an example form:
|
||||
@@ -157,7 +157,7 @@ class GenerateTemplate extends Command
|
||||
Do not ask me for more information about required properties or types, only suggest me a form structure.
|
||||
EOD;
|
||||
|
||||
const FORM_DESCRIPTION_PROMPT = <<<EOD
|
||||
public const FORM_DESCRIPTION_PROMPT = <<<'EOD'
|
||||
You are an AI assistant for OpnForm, a form builder and your job is to help us build form templates for our users.
|
||||
Give me some valid html code (using only h2, p, ul, li html tags) for the following form template page: "[REPLACE]".
|
||||
|
||||
@@ -169,12 +169,12 @@ class GenerateTemplate extends Command
|
||||
Each paragraph (except for the first one) MUST start with with a h2 tag containing a title for this paragraph.
|
||||
EOD;
|
||||
|
||||
const FORM_SHORT_DESCRIPTION_PROMPT = <<<EOD
|
||||
public const FORM_SHORT_DESCRIPTION_PROMPT = <<<'EOD'
|
||||
I own a form builder online named OpnForm. It's free to use.
|
||||
Give me a 1 sentence description for the following form template page: "[REPLACE]". It should be short and concise, but still explain what the form is about.
|
||||
EOD;
|
||||
|
||||
const FORM_INDUSTRY_PROMPT = <<<EOD
|
||||
public const FORM_INDUSTRY_PROMPT = <<<'EOD'
|
||||
You are an AI assistant for OpnForm, a form builder and your job is to help us build form templates for our users.
|
||||
I am creating a form template: "[REPLACE]". You must assign the template to industries. Return a list of industries (minimum 1, maximum 3 but only if very relevant) and order them by relevance (most relevant first).
|
||||
|
||||
@@ -185,7 +185,7 @@ class GenerateTemplate extends Command
|
||||
Ex: { "industries": ["banking_forms","customer_service_forms"]}
|
||||
EOD;
|
||||
|
||||
const FORM_TYPES_PROMPT = <<<EOD
|
||||
public const FORM_TYPES_PROMPT = <<<'EOD'
|
||||
You are an AI assistant for OpnForm, a form builder and your job is to help us build form templates for our users.
|
||||
I am creating a form template: "[REPLACE]". You must assign the template to one or more types. Return a list of types (minimum 1, maximum 3 but only if very accurate) and order them by relevance (most relevant first).
|
||||
|
||||
@@ -196,17 +196,17 @@ class GenerateTemplate extends Command
|
||||
Ex: { "types": ["consent_forms","award_forms"]}
|
||||
EOD;
|
||||
|
||||
const FORM_QAS_PROMPT = <<<EOD
|
||||
public const FORM_QAS_PROMPT = <<<'EOD'
|
||||
Now give me 4 to 6 question and answers to put on the form template page. The questions should be about the reasons for this template (when to use, why, target audience, goal etc.).
|
||||
The questions should also explain why OpnForm is the best option to create this form (open-source, free to use, integrations etc).
|
||||
Reply only with a valid JSON, being an array of object containing the keys "question" and "answer".
|
||||
EOD;
|
||||
|
||||
const FORM_TITLE_PROMPT = <<<EOD
|
||||
public const FORM_TITLE_PROMPT = <<<'EOD'
|
||||
Finally give me a title for the template. It must contain or end with "template". It should be short and to the point, without any quotes.
|
||||
EOD;
|
||||
|
||||
const FORM_IMG_KEYWORDS_PROMPT = <<<EOD
|
||||
public const FORM_IMG_KEYWORDS_PROMPT = <<<'EOD'
|
||||
I want to add an image to illustrate this form template page. Give me a relevant search query for unsplash. Reply only with a valid JSON like this:
|
||||
```json
|
||||
{
|
||||
@@ -227,14 +227,14 @@ class GenerateTemplate extends Command
|
||||
->useStreaming()
|
||||
->setSystemMessage('You are an assistant helping to generate forms.');
|
||||
$completer->expectsJson()->completeChat([
|
||||
["role" => "user", "content" => Str::of(self::FORM_STRUCTURE_PROMPT)->replace('[REPLACE]', $this->argument('prompt'))->toString()]
|
||||
['role' => 'user', 'content' => Str::of(self::FORM_STRUCTURE_PROMPT)->replace('[REPLACE]', $this->argument('prompt'))->toString()],
|
||||
]);
|
||||
$formData = $completer->getArray();
|
||||
|
||||
$completer->doesNotExpectJson();
|
||||
$formDescriptionPrompt = Str::of(self::FORM_DESCRIPTION_PROMPT)->replace('[REPLACE]', $this->argument('prompt'))->toString();
|
||||
$formShortDescription = $completer->completeChat([
|
||||
["role" => "user", "content" => Str::of(self::FORM_SHORT_DESCRIPTION_PROMPT)->replace('[REPLACE]', $this->argument('prompt'))->toString()]
|
||||
['role' => 'user', 'content' => Str::of(self::FORM_SHORT_DESCRIPTION_PROMPT)->replace('[REPLACE]', $this->argument('prompt'))->toString()],
|
||||
])->getString();
|
||||
// If description is between quotes, remove quotes
|
||||
$formShortDescription = Str::of($formShortDescription)->replaceMatches('/^"(.*)"$/', '$1')->toString();
|
||||
@@ -250,30 +250,29 @@ class GenerateTemplate extends Command
|
||||
// Now get description and QAs
|
||||
$completer->doesNotExpectJson();
|
||||
$formDescription = $completer->completeChat([
|
||||
["role" => "user", "content" => $formDescriptionPrompt]
|
||||
['role' => 'user', 'content' => $formDescriptionPrompt],
|
||||
])->getHtml();
|
||||
|
||||
$completer->expectsJson();
|
||||
$formCoverKeywords = $completer->completeChat([
|
||||
["role" => "user", "content" => $formDescriptionPrompt],
|
||||
["role" => "assistant", "content" => $formDescription],
|
||||
["role" => "user", "content" => self::FORM_IMG_KEYWORDS_PROMPT]
|
||||
['role' => 'user', 'content' => $formDescriptionPrompt],
|
||||
['role' => 'assistant', 'content' => $formDescription],
|
||||
['role' => 'user', 'content' => self::FORM_IMG_KEYWORDS_PROMPT],
|
||||
])->getArray();
|
||||
$imageUrl = $this->getImageCoverUrl($formCoverKeywords['search_query']);
|
||||
|
||||
$formQAs = $completer->completeChat([
|
||||
["role" => "user", "content" => $formDescriptionPrompt],
|
||||
["role" => "assistant", "content" => $formDescription],
|
||||
["role" => "user", "content" => self::FORM_QAS_PROMPT]
|
||||
['role' => 'user', 'content' => $formDescriptionPrompt],
|
||||
['role' => 'assistant', 'content' => $formDescription],
|
||||
['role' => 'user', 'content' => self::FORM_QAS_PROMPT],
|
||||
])->getArray();
|
||||
$completer->doesNotExpectJson();
|
||||
$formTitle = $completer->completeChat([
|
||||
["role" => "user", "content" => $formDescriptionPrompt],
|
||||
["role" => "assistant", "content" => $formDescription],
|
||||
["role" => "user", "content" => self::FORM_TITLE_PROMPT]
|
||||
['role' => 'user', 'content' => $formDescriptionPrompt],
|
||||
['role' => 'assistant', 'content' => $formDescription],
|
||||
['role' => 'user', 'content' => self::FORM_TITLE_PROMPT],
|
||||
])->getString();
|
||||
|
||||
|
||||
$template = $this->createFormTemplate(
|
||||
$formData,
|
||||
$formTitle,
|
||||
@@ -285,7 +284,7 @@ class GenerateTemplate extends Command
|
||||
$types,
|
||||
$relatedTemplates
|
||||
);
|
||||
$this->info('/form-templates/' . $template->slug);
|
||||
$this->info('/form-templates/'.$template->slug);
|
||||
|
||||
// Set reverse related Templates
|
||||
$this->setReverseRelatedTemplates($template);
|
||||
@@ -298,34 +297,37 @@ class GenerateTemplate extends Command
|
||||
*/
|
||||
private function getImageCoverUrl($searchQuery): ?string
|
||||
{
|
||||
$url = 'https://api.unsplash.com/search/photos?query=' . urlencode($searchQuery) . '&client_id=' . config('services.unsplash.access_key');
|
||||
$url = 'https://api.unsplash.com/search/photos?query='.urlencode($searchQuery).'&client_id='.config('services.unsplash.access_key');
|
||||
$response = Http::get($url)->json();
|
||||
$photoIndex = rand(0, max(count($response['results']) - 1, 10));
|
||||
if (isset($response['results'][$photoIndex]['urls']['regular'])) {
|
||||
return Str::of($response['results'][$photoIndex]['urls']['regular'])->replace('w=1080', 'w=600')->toString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getIndustries(GptCompleter $completer, string $formPrompt): array
|
||||
{
|
||||
$industriesString = Template::getAllIndustries()->pluck('slug')->join(', ');
|
||||
|
||||
return $completer->completeChat([
|
||||
["role" => "user", "content" => Str::of(self::FORM_INDUSTRY_PROMPT)
|
||||
['role' => 'user', 'content' => Str::of(self::FORM_INDUSTRY_PROMPT)
|
||||
->replace('[REPLACE]', $formPrompt)
|
||||
->replace('[INDUSTRIES]', $industriesString)
|
||||
->toString()]
|
||||
->toString()],
|
||||
])->getArray()['industries'];
|
||||
}
|
||||
|
||||
private function getTypes(GptCompleter $completer, string $formPrompt): array
|
||||
{
|
||||
$typesString = Template::getAllTypes()->pluck('slug')->join(', ');
|
||||
|
||||
return $completer->completeChat([
|
||||
["role" => "user", "content" => Str::of(self::FORM_TYPES_PROMPT)
|
||||
['role' => 'user', 'content' => Str::of(self::FORM_TYPES_PROMPT)
|
||||
->replace('[REPLACE]', $formPrompt)
|
||||
->replace('[TYPES]', $typesString)
|
||||
->toString()]
|
||||
->toString()],
|
||||
])->getArray()['types'];
|
||||
}
|
||||
|
||||
@@ -344,21 +346,21 @@ class GenerateTemplate extends Command
|
||||
}
|
||||
});
|
||||
arsort($templateScore); // Sort by Score
|
||||
|
||||
return array_slice(array_keys($templateScore), 0, self::MAX_RELATED_TEMPLATES);
|
||||
}
|
||||
|
||||
private function createFormTemplate(
|
||||
array $formData,
|
||||
string $formTitle,
|
||||
string $formDescription,
|
||||
string $formShortDescription,
|
||||
array $formQAs,
|
||||
array $formData,
|
||||
string $formTitle,
|
||||
string $formDescription,
|
||||
string $formShortDescription,
|
||||
array $formQAs,
|
||||
?string $imageUrl,
|
||||
array $industry,
|
||||
array $types,
|
||||
array $relatedTemplates
|
||||
)
|
||||
{
|
||||
array $industry,
|
||||
array $types,
|
||||
array $relatedTemplates
|
||||
) {
|
||||
// Add property uuids, improve form with options
|
||||
foreach ($formData['properties'] as &$property) {
|
||||
$property['id'] = Str::uuid()->toString(); // Column ID
|
||||
@@ -387,13 +389,15 @@ class GenerateTemplate extends Command
|
||||
'publicly_listed' => true,
|
||||
'industries' => $industry,
|
||||
'types' => $types,
|
||||
'related_templates' => $relatedTemplates
|
||||
'related_templates' => $relatedTemplates,
|
||||
]);
|
||||
}
|
||||
|
||||
private function setReverseRelatedTemplates(Template $newTemplate)
|
||||
{
|
||||
if (!$newTemplate || count($newTemplate->related_templates) === 0) return;
|
||||
if (! $newTemplate || count($newTemplate->related_templates) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$templates = Template::whereIn('slug', $newTemplate->related_templates)->get();
|
||||
foreach ($templates as $template) {
|
||||
|
||||
@@ -27,34 +27,34 @@ class GenerateTaxExport extends Command
|
||||
*/
|
||||
protected $description = 'Compute Stripe VAT per country';
|
||||
|
||||
const EU_TAX_RATES = [
|
||||
"AT" => 20,
|
||||
"BE" => 21,
|
||||
"BG" => 20,
|
||||
"HR" => 25,
|
||||
"CY" => 19,
|
||||
"CZ" => 21,
|
||||
"DK" => 25,
|
||||
"EE" => 20,
|
||||
"FI" => 24,
|
||||
"FR" => 20,
|
||||
"DE" => 19,
|
||||
"GR" => 24,
|
||||
"HU" => 27,
|
||||
"IE" => 23,
|
||||
"IT" => 22,
|
||||
"LV" => 21,
|
||||
"LT" => 21,
|
||||
"LU" => 17,
|
||||
"MT" => 18,
|
||||
"NL" => 21,
|
||||
"PL" => 23,
|
||||
"PT" => 23,
|
||||
"RO" => 19,
|
||||
"SK" => 20,
|
||||
"SI" => 22,
|
||||
"ES" => 21,
|
||||
"SE" => 25
|
||||
public const EU_TAX_RATES = [
|
||||
'AT' => 20,
|
||||
'BE' => 21,
|
||||
'BG' => 20,
|
||||
'HR' => 25,
|
||||
'CY' => 19,
|
||||
'CZ' => 21,
|
||||
'DK' => 25,
|
||||
'EE' => 20,
|
||||
'FI' => 24,
|
||||
'FR' => 20,
|
||||
'DE' => 19,
|
||||
'GR' => 24,
|
||||
'HU' => 27,
|
||||
'IE' => 23,
|
||||
'IT' => 22,
|
||||
'LV' => 21,
|
||||
'LT' => 21,
|
||||
'LU' => 17,
|
||||
'MT' => 18,
|
||||
'NL' => 21,
|
||||
'PL' => 23,
|
||||
'PT' => 23,
|
||||
'RO' => 19,
|
||||
'SK' => 20,
|
||||
'SI' => 22,
|
||||
'ES' => 21,
|
||||
'SE' => 25,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -69,20 +69,22 @@ class GenerateTaxExport extends Command
|
||||
$endDate = $this->option('end-date');
|
||||
|
||||
// Validate the date format
|
||||
if ($startDate && !Carbon::createFromFormat('Y-m-d', $startDate)) {
|
||||
if ($startDate && ! Carbon::createFromFormat('Y-m-d', $startDate)) {
|
||||
$this->error('Invalid start date format. Use YYYY-MM-DD.');
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if ($endDate && !Carbon::createFromFormat('Y-m-d', $endDate)) {
|
||||
if ($endDate && ! Carbon::createFromFormat('Y-m-d', $endDate)) {
|
||||
$this->error('Invalid end date format. Use YYYY-MM-DD.');
|
||||
|
||||
return Command::FAILURE;
|
||||
} else if (!$endDate && $this->option('full-month')) {
|
||||
} elseif (! $endDate && $this->option('full-month')) {
|
||||
$endDate = Carbon::parse($startDate)->endOfMonth()->endOfDay()->format('Y-m-d');
|
||||
}
|
||||
|
||||
$this->info('Start date: ' . $startDate);
|
||||
$this->info('End date: ' . $endDate);
|
||||
$this->info('Start date: '.$startDate);
|
||||
$this->info('End date: '.$endDate);
|
||||
|
||||
$processedInvoices = [];
|
||||
|
||||
@@ -111,6 +113,7 @@ class GenerateTaxExport extends Command
|
||||
// Ignore if payment was refunded
|
||||
if (($invoice->payment_intent->status ?? null) !== 'succeeded') {
|
||||
$paymentNotSuccessfulCount++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -132,14 +135,14 @@ class GenerateTaxExport extends Command
|
||||
|
||||
$aggregatedReport = $this->aggregateReport($processedInvoices);
|
||||
|
||||
$filePath = 'opnform-tax-export-per-invoice_' . $startDate . '_' . $endDate . '.xlsx';
|
||||
$filePath = 'opnform-tax-export-per-invoice_'.$startDate.'_'.$endDate.'.xlsx';
|
||||
$this->exportAsXlsx($processedInvoices, $filePath);
|
||||
|
||||
$aggregatedReportFilePath = 'opnform-tax-export-aggregated_' . $startDate . '_' . $endDate . '.xlsx';
|
||||
$aggregatedReportFilePath = 'opnform-tax-export-aggregated_'.$startDate.'_'.$endDate.'.xlsx';
|
||||
$this->exportAsXlsx($aggregatedReport, $aggregatedReportFilePath);
|
||||
|
||||
// Display the results
|
||||
$this->info('Total invoices: ' . $totalInvoice . ' (with ' . $paymentNotSuccessfulCount . ' payment not successful or trial free invoice)');
|
||||
$this->info('Total invoices: '.$totalInvoice.' (with '.$paymentNotSuccessfulCount.' payment not successful or trial free invoice)');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
@@ -151,7 +154,7 @@ class GenerateTaxExport extends Command
|
||||
foreach ($invoices as $invoice) {
|
||||
$country = $invoice['cust_country'];
|
||||
$customerType = is_null($invoice['cust_vat_id']) && $this->isEuropeanCountry($country) ? 'individual' : 'business';
|
||||
if (!isset($aggregatedReport[$country])) {
|
||||
if (! isset($aggregatedReport[$country])) {
|
||||
$defaultVal = [
|
||||
'count' => 0,
|
||||
'total_usd' => 0,
|
||||
@@ -163,7 +166,7 @@ class GenerateTaxExport extends Command
|
||||
];
|
||||
$aggregatedReport[$country] = [
|
||||
'individual' => $defaultVal,
|
||||
'business' => $defaultVal
|
||||
'business' => $defaultVal,
|
||||
];
|
||||
}
|
||||
$aggregatedReport[$country][$customerType]['count']++;
|
||||
@@ -181,10 +184,11 @@ class GenerateTaxExport extends Command
|
||||
$finalReport[] = [
|
||||
'country' => $country,
|
||||
'customer_type' => $customerType,
|
||||
...$aggData
|
||||
...$aggData,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $finalReport;
|
||||
}
|
||||
|
||||
@@ -226,7 +230,9 @@ class GenerateTaxExport extends Command
|
||||
|
||||
if ($taxRate = (self::EU_TAX_RATES[$countryCode] ?? null)) {
|
||||
// If VAT ID is provided, then TAX is 0%
|
||||
if (!$vatId) return $taxRate;
|
||||
if (! $vatId) {
|
||||
return $taxRate;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -241,12 +247,11 @@ class GenerateTaxExport extends Command
|
||||
{
|
||||
if (count($data) == 0) {
|
||||
$this->info('Empty data. No file generated.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
(new ArrayExport($data))->store($filename, 'local', \Maatwebsite\Excel\Excel::XLSX);
|
||||
$this->line('File generated: ' . storage_path('app/' . $filename));
|
||||
$this->line('File generated: '.storage_path('app/'.$filename));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user