Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clone estimates #97

Merged
merged 7 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ DB_PASSWORD="invoiceshelf"

BROADCAST_CONNECTION=log
CACHE_STORE=file
QUEUE_DRIVER=sync
QUEUE_CONNECTION=sync
SESSION_DRIVER=cookie
SESSION_LIFETIME=1440
SESSION_ENCRYPT=false
Expand Down
131 changes: 131 additions & 0 deletions app/Http/Controllers/V1/Admin/Estimate/CloneEstimateController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?php

namespace App\Http\Controllers\V1\Admin\Estimate;

use App\Http\Controllers\Controller;
use App\Http\Resources\EstimateResource;
use App\Models\CompanySetting;
use App\Models\Estimate;
use App\Services\SerialNumberFormatter;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Vinkla\Hashids\Facades\Hashids;

class CloneEstimateController extends Controller
{
/**
* Mail a specific invoice to the corresponding customer's email address.
*
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request, Estimate $estimate)
{
$this->authorize('create', Estimate::class);

$date = Carbon::now();

$serial = (new SerialNumberFormatter())
->setModel($estimate)
->setCompany($estimate->company_id)
->setCustomer($estimate->customer_id)
->setNextNumbers();

$due_date = null;
$dueDateEnabled = CompanySetting::getSetting(
'estimate_set_expiry_date_automatically',
$request->header('company')
);

if ($dueDateEnabled === 'YES') {
$dueDateDays = intval(CompanySetting::getSetting(
'estimate_expiry_date_days',
$request->header('company')
));
$due_date = Carbon::now()->addDays($dueDateDays)->format('Y-m-d');
}

$exchange_rate = $estimate->exchange_rate;

$newEstimate = Estimate::create([
'estimate_date' => $date->format('Y-m-d'),
'expiry_date' => $due_date,
'estimate_number' => $serial->getNextNumber(),
'sequence_number' => $serial->nextSequenceNumber,
'customer_sequence_number' => $serial->nextCustomerSequenceNumber,
'reference_number' => $estimate->reference_number,
'customer_id' => $estimate->customer_id,
'company_id' => $request->header('company'),
'template_name' => $estimate->template_name,
'status' => Estimate::STATUS_DRAFT,
'sub_total' => $estimate->sub_total,
'discount' => $estimate->discount,
'discount_type' => $estimate->discount_type,
'discount_val' => $estimate->discount_val,
'total' => $estimate->total,
'due_amount' => $estimate->total,
'tax_per_item' => $estimate->tax_per_item,
'discount_per_item' => $estimate->discount_per_item,
'tax' => $estimate->tax,
'notes' => $estimate->notes,
'exchange_rate' => $exchange_rate,
'base_total' => $estimate->total * $exchange_rate,
'base_discount_val' => $estimate->discount_val * $exchange_rate,
'base_sub_total' => $estimate->sub_total * $exchange_rate,
'base_tax' => $estimate->tax * $exchange_rate,
'base_due_amount' => $estimate->total * $exchange_rate,
'currency_id' => $estimate->currency_id,
'sales_tax_type' => $estimate->sales_tax_type,
'sales_tax_address_type' => $estimate->sales_tax_address_type,
]);

$newEstimate->unique_hash = Hashids::connection(Estimate::class)->encode($newEstimate->id);
$newEstimate->save();
$estimate->load('items.taxes');

$estimateItems = $estimate->items->toArray();

foreach ($estimateItems as $estimateItem) {
$estimateItem['company_id'] = $request->header('company');
$estimateItem['name'] = $estimateItem['name'];
$estimateItem['exchange_rate'] = $exchange_rate;
$estimateItem['base_price'] = $estimateItem['price'] * $exchange_rate;
$estimateItem['base_discount_val'] = $estimateItem['discount_val'] * $exchange_rate;
$estimateItem['base_tax'] = $estimateItem['tax'] * $exchange_rate;
$estimateItem['base_total'] = $estimateItem['total'] * $exchange_rate;

$item = $newEstimate->items()->create($estimateItem);

if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) {
foreach ($estimateItem['taxes'] as $tax) {
$tax['company_id'] = $request->header('company');

if ($tax['amount']) {
$item->taxes()->create($tax);
}
}
}
}

if ($estimate->taxes) {
foreach ($estimate->taxes->toArray() as $tax) {
$tax['company_id'] = $request->header('company');
$newEstimate->taxes()->create($tax);
}
}

if ($estimate->fields()->exists()) {
$customFields = [];

foreach ($estimate->fields as $data) {
$customFields[] = [
'id' => $data->custom_field_id,
'value' => $data->defaultAnswer,
];
}

$newEstimate->addCustomFields($customFields);
}

return new EstimateResource($newEstimate);
}
}
11 changes: 10 additions & 1 deletion app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,16 @@ class AppServiceProvider extends ServiceProvider
*
* @var string
*/
public const HOME = '/home';
public const HOME = '/admin/dashboard';

/**
* The path to the "customer home" route for your application.
*
* This is used by Laravel authentication to redirect customers after login.
*
* @var string
*/
public const CUSTOMER_HOME = '/customer/dashboard';

/**
* Bootstrap any application services.
Expand Down
3 changes: 3 additions & 0 deletions lang/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "تسجيل مدفوات",
"add_estimate": "إضافة تقدير",
"save_estimate": "حفظ التقدير",
"cloned_successfully": "تم استنساخ العرض بنجاح",
"clone_estimate": "استنساخ العرض",
"confirm_clone": "سيتم استنساخ هذا العرض إلى عرض جديد",
"confirm_conversion": "هل تريد تحويل هذا التقدير إلى فاتورة؟",
"conversion_message": "تم إنشاء الفاتورة بنجاح",
"confirm_send_estimate": "سيتم إرسال هذا التقدير بالبريد الإلكتروني إلى العميل",
Expand Down
3 changes: 3 additions & 0 deletions lang/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Zaznamenat platbu",
"add_estimate": "Přidat nabídku",
"save_estimate": "Uložit nabídku",
"cloned_successfully": "Devis úspěšně zkopírován",
"clone_estimate": "Klonovat devis",
"confirm_clone": "Tento devis bude zkopírován do nového devisu",
"confirm_conversion": "Tento odhad bude použit k vytvoření nové faktury.",
"conversion_message": "Faktura byla úspěšně vytvořena",
"confirm_send_estimate": "Tento odhad bude zaslán e-mailem zákazníkovi",
Expand Down
3 changes: 3 additions & 0 deletions lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Zahlung erfassen",
"add_estimate": "Angebote hinzufügen",
"save_estimate": "Angebot speichern",
"cloned_successfully": "Angebot erfolgreich geklont",
"clone_estimate": "Angebot klonen",
"confirm_clone": "Dieses Angebot wird in ein neues Angebot kopiert",
"confirm_conversion": "Dieses Angebot wird verwendet, um eine neue Rechnung zu erstellen.",
"conversion_message": "Rechnung erfolgreich erstellt",
"confirm_send_estimate": "Das Angebot wird per E-Mail an den Kunden gesendet",
Expand Down
3 changes: 3 additions & 0 deletions lang/el.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Καταγραφή Πληρωμής",
"add_estimate": "Νέα Εκτίμηση",
"save_estimate": "Νέα Εκτίμηση",
"cloned_successfully": "Η προσφορά κλωνοποιήθηκε με επιτυχία",
"clone_estimate": "Κλωνοποίηση προσφοράς",
"confirm_clone": "Αυτή η προσφορά θα κλωνοποιηθεί σε μια νέα προσφορά",
"confirm_conversion": "Αυτή η εκτίμηση θα χρησιμοποιηθεί για τη δημιουργία ενός νέου τιμολογίου.",
"conversion_message": "Το τιμολόγιο κλωνοποιήθηκε επιτυχώς",
"confirm_send_estimate": "Αυτό το τιμολόγιο θα αποσταλεί μέσω email στον πελάτη",
Expand Down
3 changes: 3 additions & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Record Payment",
"add_estimate": "Add Estimate",
"save_estimate": "Save Estimate",
"cloned_successfully": "Estimate cloned successfully",
"clone_estimate": "Clone Estimate",
"confirm_clone": "This Estimate will be cloned into a new Estimate",
"confirm_conversion": "This estimate will be used to create a new Invoice.",
"conversion_message": "Invoice created successful",
"confirm_send_estimate": "This estimate will be sent via email to the customer",
Expand Down
3 changes: 3 additions & 0 deletions lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Registro de pago",
"add_estimate": "Agregar presupuesto",
"save_estimate": "Guardar presupuesto",
"cloned_successfully": "Presupuesto clonado con éxito",
"clone_estimate": "Clonar presupuesto",
"confirm_clone": "Este presupuesto será clonado en un nuevo presupuesto",
"confirm_conversion": "¿Quiere convertir este presupuesto en una factura?",
"conversion_message": "Conversión exitosa",
"confirm_send_estimate": "Este presupuesto se enviará por correo electrónico al cliente",
Expand Down
3 changes: 3 additions & 0 deletions lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Enregistrer un paiement",
"add_estimate": "Nouveau devis",
"save_estimate": "Enregistrer",
"cloned_successfully": "Devis dupliqué avec succès",
"clone_estimate": "Dupliquer le devis",
"confirm_clone": "Ce devis sera dupliqué dans un nouveau devis",
"confirm_conversion": "Ce devis sera utilisé pour créer une nouvelle facture.",
"conversion_message": "Conversion réussie",
"confirm_send_estimate": "Ce devis sera envoyée par email au client",
Expand Down
3 changes: 3 additions & 0 deletions lang/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Registra Pagamento",
"add_estimate": "Aggiungi Preventivo",
"save_estimate": "Salva Preventivo",
"cloned_successfully": "Preventivo clonato con successo",
"clone_estimate": "Clonare preventivo",
"confirm_clone": "Questo preventivo sarà clonato in un nuovo preventivo",
"confirm_conversion": "Questo preventivo verrà usato per generare una nuova fattura.",
"conversion_message": "Fattura creata",
"confirm_send_estimate": "Questo preventivo verrà inviato al cliente via mail",
Expand Down
3 changes: 3 additions & 0 deletions lang/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Record Payment",
"add_estimate": "Add Estimate",
"save_estimate": "Save Estimate",
"cloned_successfully": "見積もりが正常にクローンされました",
"clone_estimate": "見積もりをクローン",
"confirm_clone": "この見積もりは新しい見積もりにクローンされます",
"confirm_conversion": "This estimate will be used to create a new Invoice.",
"conversion_message": "Invoice created successful",
"confirm_send_estimate": "This estimate will be sent via email to the customer",
Expand Down
3 changes: 3 additions & 0 deletions lang/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@
"record_payment": "기록 지불",
"add_estimate": "견적 추가",
"save_estimate": "견적 저장",
"cloned_successfully": "견적이 성공적으로 복제되었습니다",
"clone_estimate": "견적 복제",
"confirm_clone": "이 견적은 새로운 견적으로 복제될 것입니다",
"confirm_conversion": "이 견적은 새 인보이스를 만드는 데 사용됩니다.",
"conversion_message": "인보이스가 성공적으로 생성되었습니다.",
"confirm_send_estimate": "이 견적은 이메일을 통해 고객에게 전송됩니다.",
Expand Down
3 changes: 3 additions & 0 deletions lang/lv.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Izveidot maksājumu",
"add_estimate": "Pievienot aprēķinu",
"save_estimate": "Saglabāt aprēķinu",
"cloned_successfully": "Piedāvājums veiksmīgi klonēts",
"clone_estimate": "Klonēt piedāvājumu",
"confirm_clone": "Šis piedāvājums tiks klonēts jaunā piedāvājumā",
"confirm_conversion": "Šis aprēķins tiks izmantots, lai izveidotu jaunu rēķinu.",
"conversion_message": "Rēķins izveidots veiksmīgi",
"confirm_send_estimate": "Šis aprēķins tiks nosūtīts klientam e-pastā",
Expand Down
3 changes: 3 additions & 0 deletions lang/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Betaling registreren",
"add_estimate": "Offerte toevoegen",
"save_estimate": "Bewaar offerte",
"cloned_successfully": "Offerte succesvol gekloond",
"clone_estimate": "Offerte klonen",
"confirm_clone": "Deze offerte zal worden gekopieerd naar een nieuwe offerte",
"confirm_conversion": "Deze offerte wordt gebruikt om een nieuwe factuur te maken.",
"conversion_message": "Factuur gemaakt",
"confirm_send_estimate": "Deze offerte wordt via e-mail naar de klant gestuurd",
Expand Down
3 changes: 3 additions & 0 deletions lang/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Zarejestruj płatność",
"add_estimate": "Dodaj ofertę",
"save_estimate": "Zapisz ofertę",
"cloned_successfully": "Oferta została pomyślnie sklonowana",
"clone_estimate": "Sklonuj ofertę",
"confirm_clone": "Ta oferta zostanie sklonowana do nowej oferty",
"confirm_conversion": "Ta oferta zostanie użyta do utworzenia nowej faktury.",
"conversion_message": "Faktura została utworzona pomyślnie",
"confirm_send_estimate": "Ta oferta zostanie wysłana pocztą elektroniczną do kontrahenta",
Expand Down
3 changes: 3 additions & 0 deletions lang/pt-br.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@
"record_payment": "Registro de pago",
"add_estimate": "Adicionar orçamento",
"save_estimate": "Salvar Orçamento",
"cloned_successfully": "Orçamento clonado com sucesso",
"clone_estimate": "Clonar orçamento",
"confirm_clone": "Este orçamento será clonado em um novo orçamento",
"confirm_conversion": "Deseja converter este orçamento em uma fatura?",
"conversion_message": "Converção realizada com sucesso",
"confirm_send_estimate": "Este orçamento será enviado por email ao cliente",
Expand Down
3 changes: 3 additions & 0 deletions lang/sk.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Zaznamenať Platbu",
"add_estimate": "Vytvoriť Cenový odhad",
"save_estimate": "Uložiť Cenový odhad",
"cloned_successfully": "Ponuka úspešne skopírovaná",
"clone_estimate": "Klonovať ponuku",
"confirm_clone": "Táto ponuka bude skopírovaná do novej ponuky",
"confirm_conversion": "Tento cenový odhad bude použitý k vytvoreniu novej Faktúry.",
"conversion_message": "Faktúra úspešne vytvorená",
"confirm_send_estimate": "Tento Cenový odhad bude odoslaný zákazníkovi prostredníctvom e-mailu",
Expand Down
3 changes: 3 additions & 0 deletions lang/sr.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Unesi uplatu",
"add_estimate": "Dodaj Profakturu",
"save_estimate": "Sačuvaj Profakturu",
"cloned_successfully": "Ponuda uspešno klonirana",
"clone_estimate": "Kloniraj ponudu",
"confirm_clone": "Ova ponuda će biti klonirana u novu ponudu",
"confirm_conversion": "Detalji ove Profakture će biti iskorišćeni za pravljenje Fakture.",
"conversion_message": "Faktura uspešno kreirana",
"confirm_send_estimate": "Ova Profaktura će biti poslata putem Email-a klijentu",
Expand Down
3 changes: 3 additions & 0 deletions lang/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
"record_payment": "Registrera betalning",
"add_estimate": "Lägg till kostnadsförslag",
"save_estimate": "Spara kostnadsförslag",
"cloned_successfully": "Offert klonades framgångsrikt",
"clone_estimate": "Klona offert",
"confirm_clone": "Denna offert kommer att klonas till en ny offert",
"confirm_conversion": "Detta kostnadsförslag används för att skapa ny faktura.",
"conversion_message": "Faktura skapades",
"confirm_send_estimate": "Detta kostnadsförslag skickas via epost till kund",
Expand Down
3 changes: 3 additions & 0 deletions lang/th.json
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@
"record_payment": "บันทึกการชำระเงิน",
"add_estimate": "เพิ่มค่าใบเสนอราคา",
"save_estimate": "บันทึกใบเสนอราคา",
"cloned_successfully": "โคลนข้อเสนอสำเร็จ",
"clone_estimate": "โคลนข้อเสนอ",
"confirm_clone": "ข้อเสนอนี้จะถูกโคลนเป็นข้อเสนอใหม่",
"confirm_conversion": "ใบเสนอราคานี้จะใช้ในการสร้างใบวางบิลใหม่",
"conversion_message": "ใบวางบิลที่สร้างเสร็จสมบูรณ์",
"confirm_send_estimate": "ใบเสนอราคานี้จะถูกส่งผ่านทางอีเมลถึงลูกค้า",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@
</BaseDropdownItem>
</router-link>

<!-- Clone Estimate into new estimate -->
<BaseDropdownItem
v-if="userStore.hasAbilities(abilities.CREATE_ESTIMATE)"
@click="cloneEstimateData(row)"
>
<BaseIcon
name="DocumentTextIcon"
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
/>
{{ $t('estimates.clone_estimate') }}
</BaseDropdownItem>

<!-- Convert into Invoice -->
<BaseDropdownItem
v-if="userStore.hasAbilities(abilities.CREATE_INVOICE)"
Expand Down Expand Up @@ -334,4 +346,24 @@ function copyPdfUrl() {
message: t('general.copied_pdf_url_clipboard'),
})
}

async function cloneEstimateData(data) {
dialogStore
.openDialog({
title: t('general.are_you_sure'),
message: t('estimates.confirm_clone'),
yesLabel: t('general.ok'),
noLabel: t('general.cancel'),
variant: 'primary',
hideNoButton: false,
size: 'lg',
})
.then((res) => {
if (res) {
estimateStore.cloneEstimate(data).then((res) => {
router.push(`/admin/estimates/${res.data.data.id}/edit`)
})
}
})
}
</script>
Loading
Loading