AddAccountReceivableDialog.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <template>
  2. <q-dialog ref="dialogRef" @hide="onDialogHide">
  3. <q-card
  4. class="q-dialog-plugin overflow-hidden"
  5. style="width: 520px; max-width: 90vw"
  6. >
  7. <DefaultDialogHeader
  8. title="Nova conta a receber"
  9. @close="onDialogCancel"
  10. />
  11. <DefaultForm ref="formRef" @submit.prevent="onSubmit">
  12. <q-scroll-area ref="scrollAreaRef" class="form-dialog-scroll-area">
  13. <q-card-section class="row q-col-gutter-md q-pt-none">
  14. <DefaultInput
  15. v-model="form.history"
  16. v-model:error="validationErrors.history"
  17. class="col-12"
  18. label="Descrição"
  19. :error-message="validationErrors.history"
  20. :rules="[inputRules.required, inputRules.max(255)]"
  21. />
  22. <div class="col-12">
  23. <div class="text-caption text-grey-8 q-mb-xs">
  24. Tipo da conta <span class="text-negative">*</span>
  25. </div>
  26. <q-option-group
  27. v-model="form.account_type"
  28. color="primary"
  29. inline
  30. type="radio"
  31. :options="accountTypeOptions"
  32. />
  33. </div>
  34. <UnitSelect
  35. v-if="form.account_type === 'unit'"
  36. v-model="form.unit"
  37. v-model:error="validationErrors.unit_id"
  38. class="col-12"
  39. label="Unidade"
  40. :error-message="validationErrors.unit_id"
  41. :rules="[inputRules.required]"
  42. />
  43. <DefaultCurrencyInput
  44. v-model="form.value"
  45. v-model:error="validationErrors.value"
  46. class="col-12 col-sm-6"
  47. label="Valor"
  48. :error-message="validationErrors.value"
  49. :rules="[inputRules.requiredNumber, inputRules.minValue(0.01)]"
  50. />
  51. <DefaultInputDatePicker
  52. v-model="form.due_date"
  53. v-model:untreated-date="form.due_date_iso"
  54. v-model:error="validationErrors.due_date"
  55. class="col-12 col-sm-6"
  56. label="Data de vencimento"
  57. :error-message="validationErrors.due_date"
  58. :rules="[inputRules.required]"
  59. />
  60. <DefaultSelect
  61. v-model="form.financial_plan_account_id"
  62. v-model:error="validationErrors.financial_plan_account_id"
  63. class="col-12"
  64. clearable
  65. emit-value
  66. label="Plano de contas"
  67. map-options
  68. :error-message="validationErrors.financial_plan_account_id"
  69. :options="planAccountOptions"
  70. :loading="loadingPlanAccounts"
  71. />
  72. <DefaultInput
  73. v-model="form.obs"
  74. v-model:error="validationErrors.obs"
  75. class="col-12"
  76. label="Observação"
  77. rows="3"
  78. type="textarea"
  79. :error-message="validationErrors.obs"
  80. :rules="[inputRules.max(1000)]"
  81. />
  82. </q-card-section>
  83. </q-scroll-area>
  84. <q-separator />
  85. <q-card-actions align="right" class="q-pa-md q-gutter-sm">
  86. <q-btn
  87. color="negative"
  88. label="Cancelar"
  89. no-caps
  90. outline
  91. @click="onDialogCancel"
  92. />
  93. <q-btn
  94. color="primary"
  95. label="Salvar"
  96. no-caps
  97. type="submit"
  98. unelevated
  99. :loading="loading"
  100. />
  101. </q-card-actions>
  102. </DefaultForm>
  103. </q-card>
  104. </q-dialog>
  105. </template>
  106. <script setup>
  107. import { createFranchiseeReceivable } from "src/api/franchisee_account_receive";
  108. import { getFinancialPlanAccountsForSelect } from "src/api/financial_plan_account";
  109. import { onMounted, ref, watch } from "vue";
  110. import { useDialogPluginComponent } from "quasar";
  111. import { useForm } from "src/composables/useForm";
  112. import { useInputRules } from "src/composables/useInputRules";
  113. import { useScroll } from "src/composables/useScroll";
  114. import { useSubmitHandler } from "src/composables/useSubmitHandler";
  115. import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.vue";
  116. import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
  117. import DefaultInput from "src/components/defaults/DefaultInput.vue";
  118. import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";
  119. import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
  120. import UnitSelect from "src/components/selects/UnitSelect.vue";
  121. defineEmits([...useDialogPluginComponent.emits]);
  122. const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
  123. useDialogPluginComponent();
  124. const today = new Date();
  125. const dueDateIso = [
  126. today.getFullYear(),
  127. String(today.getMonth() + 1).padStart(2, "0"),
  128. String(today.getDate()).padStart(2, "0"),
  129. ].join("-");
  130. const accountTypeOptions = [
  131. { label: "Conta interna", value: "internal" },
  132. { label: "Relacionada a uma unidade", value: "unit" },
  133. ];
  134. const formRef = ref(null);
  135. const scrollAreaRef = ref(null);
  136. const { inputRules } = useInputRules();
  137. const { scrollToComponent } = useScroll();
  138. const { form } = useForm(
  139. {
  140. account_type: "internal",
  141. unit: null,
  142. history: "",
  143. value: 0,
  144. due_date: today.toLocaleDateString("pt-BR"),
  145. due_date_iso: dueDateIso,
  146. financial_plan_account_id: null,
  147. obs: "",
  148. },
  149. { containerRef: scrollAreaRef },
  150. );
  151. const {
  152. loading,
  153. validationErrors,
  154. execute: submitForm,
  155. } = useSubmitHandler({
  156. formRef,
  157. containerRef: scrollAreaRef,
  158. scrollFn: scrollToComponent,
  159. onSuccess: (response) => onDialogOK(response),
  160. });
  161. const planAccountOptions = ref([]);
  162. const loadingPlanAccounts = ref(false);
  163. const onSubmit = async () => {
  164. await submitForm(() =>
  165. createFranchiseeReceivable({
  166. account_type: form.account_type,
  167. unit_id: form.account_type === "unit" ? form.unit?.value : null,
  168. history: form.history,
  169. value: form.value,
  170. due_date: form.due_date_iso,
  171. financial_plan_account_id: form.financial_plan_account_id || null,
  172. obs: form.obs || null,
  173. }),
  174. );
  175. };
  176. watch(
  177. () => form.account_type,
  178. (type) => {
  179. if (type === "internal") form.unit = null;
  180. },
  181. );
  182. onMounted(async () => {
  183. loadingPlanAccounts.value = true;
  184. try {
  185. const accounts = await getFinancialPlanAccountsForSelect();
  186. planAccountOptions.value = (accounts ?? []).map((account) => ({
  187. label: `${account.code} — ${account.description}`,
  188. value: account.id,
  189. }));
  190. } finally {
  191. loadingPlanAccounts.value = false;
  192. }
  193. });
  194. </script>