Spamworldpro Mini Shell
Spamworldpro


Server : Apache
System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64
User : corals ( 1002)
PHP Version : 7.4.33
Disable Function : exec,passthru,shell_exec,system
Directory :  /home/corals/ts.corals.io/frontend/pages/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/corals/ts.corals.io/frontend/pages/expenses.vue
<template>
  <div>
    <CRUDIndex ref="expensesTable" :columns="columns" :resourceURL="resourceUrl" :options="options" :form="form"
               :bulk-action-options="bulkActionOptions" :labels="labels" :cloneAttr="cloneAttr" form-size="lg">
      <template v-slot:user_id="{object}">
        {{ object.row.user }}
      </template>

      <template v-slot:project="{object}">
        <nuxt-link :to="`/clients/${object.row.client_id}/projects/${object.row.project_id}`">
          {{ object.row.project }}
        </nuxt-link>
      </template>

      <template v-slot:client="{object}">
        <nuxt-link :to="'/clients/'+object.row.client_id">
          {{ object.row.client }}
        </nuxt-link>
      </template>

      <template v-slot:payment_method="{object}">
        {{ object.row.payment_method }}
      </template>

      <template v-slot:category_id="{object}">
        {{ object.row.category }}
      </template>

      <template v-slot:file="{object}">
        <a :href="object.row.file" target="_blank" v-if="object.row.file">File</a>
        <span v-else>-</span>
      </template>

      <template v-slot:status="{object}">
        <span v-html="object.row.status"></span>
      </template>
      <template v-slot:invoice="{object}">
        <nuxt-link :to="'/invoices/'+object.row.invoice_id"
                   v-if="object.row.invoice_id && object.row.invoice_id !== '-'">
          {{ object.row.invoice_code }}
        </nuxt-link>
        <span v-else-if="object.row.billable">
          Not Invoiced
        </span>
        <span v-else>
          -
        </span>
      </template>
      <template v-slot:default="{form}">
        <div class="" v-if="!form.id">
          <div class="custom-control custom-checkbox mb-2">
            <input type="checkbox" id="active_options" class="custom-control-input"
                   v-model="active_options"/>
            <label for="active_options" class="custom-control-label">
              <small>Show Active Options</small>
            </label>
          </div>
        </div>

        <div class="row sm-gutters">
          <div class="col-md-5">
            <corals-datepicker :form="form" required field="expense_date" label="Expense Date"/>
          </div>
          <div class="col-md-4">
            <corals-input :form="form" type="number" field="amount" step="0.1" required min="0"/>
          </div>
          <div class="col-md-3">
            <corals-select :form="form" field="currency" :options="form.getFormData('currency_options')" required/>
          </div>
        </div>

        <div class="row sm-gutters">
          <div class="col-md-5">
            <corals-select :form="form" required label="Category" field="category_id"
                           :options="getCategoriesOrProjectsOptions(form.getFormData('categories'))"/>

            <corals-checkbox field="billable" :form="form" description="It will be included in the next client invoice when project selected"/>
          </div>
          <div class="col-md-7">
            <corals-textarea field="notes" required rows="3" :form="form"/>
          </div>
        </div>

        <div class="row sm-gutters">
          <div class="col-md-5">
            <corals-select :form="form" label="Project" field="project_id"
                           :options="getCategoriesOrProjectsOptions(form.getFormData('projects'))"/>
          </div>
          <div class="col-md-7">
            <corals-select :form="form" label="User" field="user_id"
                           :options="form.getFormData('users')"/>
          </div>
        </div>
        <div class="row sm-gutters">
          <div class="col-md-6">
            <corals-radio :form="form" label="Payment Method" field="payment_method"
                          :list="form.getFormData('payment_method_options')" required/>
          </div>
          <div class="col-md-6">
            <corals-radio :form="form" field="status" required label="Status"
                          :list="form.getFormData('status_options')"/>
          </div>
        </div>
        <div class="row sm-gutters">
          <div class="col-md-6">
            <label>Attachment</label>
            <div v-if="filePath">
              <a :href="filePath" target="_blank">Show File</a>
              <corals-checkbox field="clear" :form="form"/>
            </div>
            <div class="mb-2">
              <b-form-file v-model="form.file"
                           placeholder="Upload File..."></b-form-file>
              <span v-if="filePath && form.file" class="text-muted small">Note: when a new file is uploaded, the existing file is automatically deleted</span>
            </div>
          </div>
        </div>
      </template>
      <template v-slot:extra-actions="{object}">
        <b-link @click.prevent="generateInvoiceForExpense(object)"
                title="Generate an Invoice"
                v-if="object.generateInvoice">
          <fa icon="file-invoice" class="text-success"/>
        </b-link>
      </template>
    </CRUDIndex>
  </div>
</template>

<script>
import CRUDIndex from "@/components/layout/CRUDIndex";
import commonMixin from "@/mixins/commonMixin";
import CoralsSelect from "@/components/CoralsForm/CoralsSelect";

export default {
  name: "index",
  components: {CoralsSelect, CRUDIndex},
  middleware: 'Authorization',
  mixins: [commonMixin],
  provide() {
    return {
      handleBulkAction: this.handleBulkAction,
    }
  },
  data() {
    return {
      active_options: 1,
      filePath: null,
      resourceUrl: 'timesheet/expenses',
      labels: {
        title: 'Expenses',
        singularTitle: 'Expense',
      },
      cloneAttr: {
        category_id: null,
        project_id: null,
        client_id: null,
        notes: null,
        amount: null,
        expense_date: new Date(),
        billable: null,
        status: null,
        currency: null,
        payment_method: null,
      },
      options: {
        listColumns: {
          billable: this.yesNoOptions(),
          status: [],
          payment_method: [],
          category_id: [],
          user_id: [],
        },
        customColumns: ['status', 'project', 'client', 'payment_method', 'file', 'user_id', 'category_id', 'invoice'],
        filterable: ['status', 'payment_method', 'expense_date', 'category_id', 'project', 'client', 'notes', 'user_id', 'invoice'],
        hideCreate: this.$cant('create', 'expense'),
        headings: {
          'payment_method': 'Payment Method',
          'category_id': 'Category',
          'user_id': 'User',
        },
      },
      form: this.$form({
        id: null,
        category_id: '',
        project_id: '',
        client_id: '',
        user_id: '',
        notes: '',
        amount: '',
        status: 'paid',
        file: null,
        clear: 0,
        expense_date: new Date(),
        billable: 0,
        currency: 'usd',
        payment_method: 'paypal',
      }, {
        fetchFormDataURL: '/timesheet/expenses/get-form-data',
        model: 'expense',
        loadFormDataCallBack: () => {
          this.options.listColumns.status = this.getOptions(this.form.formData.status_options);

          let categories = JSON.parse(JSON.stringify(this.form.formData.categories));
          categories.shift();
          this.options.listColumns.category_id = this.getOptions(categories);

          this.options.listColumns.payment_method = this.getOptions(this.form.formData.payment_method_options);

          this.options.listColumns.user_id = this.getOptions(this.form.formData.users);
        }
      }),
    }
  },
  methods: {
    generateInvoiceForExpense(expense) {
      this.$swal.fire({
        title: 'Are you sure?',
        text: "You wont to generate invoice for this expenses?",
        icon: 'warning',
        showCancelButton: true,
        confirmButtonColor: '#14A44D',
        cancelButtonColor: '#d7d7d7',
        confirmButtonText: 'Yes, Generate it!'
      }).then((result) => {
        if (result.value) {
          this.$axios.post(`timesheet/expenses/${expense.id}/generate-invoice`)
            .then(response => {
            let level = response.data.data.level;
            let message = response.data.data.message;

            if (level === 'success') {
              this.$toast.success(message);
            } else {
              this.$toast.error(message);
            }
            this.$refs.expensesTable.refresh();
          })
        }
      })
    },
    getOptions(list) {
      let allOption = {id: '', text: 'All'};
      let options = [];

      options.push(allOption);

      list.map(row => {
        let label = row.label.split(",");
        options.push({id: row.id ?? row.value, text: label[0]});
      });

      return options;
    },
    getCategoriesOrProjectsOptions(arrayData) {
      let resultsData = [];
      let DataGroups = [];
      let activeObjects = [];

      if (!this.active_options) {
        activeObjects = arrayData.filter((object => object['group'] !== true));
        DataGroups = arrayData.filter((group => group['group'] === true));
      } else {
        activeObjects = arrayData.filter((object => (object['is_active'] === 1 || object['status'] === 'active') && object['group'] !== true));
        DataGroups = arrayData.filter((group => group['group'] === true && group['status'] === 'active'));
      }
      DataGroups.forEach(group => {
        group['is_group_empty'] = true;
        resultsData.push(group);
        activeObjects.filter(activeObject => {
          if (group['code'] === activeObject['group']) {
            group['is_group_empty'] = false;
            resultsData.push(activeObject);
          }
        });
      });
      return resultsData;
    },
    handleBulkAction(action, selectedIds) {
      this.$bvModal.msgBoxConfirm('Are you sure?', {
        size: 'md',
        buttonSize: 'sm',
        okVariant: 'danger',
        footerClass: 'p-2',
        hideHeaderClose: false,
        centered: true
      })
        .then(value => {
          if (value === true) {
            this.$axios.post('timesheet/expenses/bulk-action', {
              'selection': selectedIds,
              'action': action
            }).then(response => {
              let level = response.data.data.level;
              let message = response.data.data.message;

              if (level === 'success') {
                this.$toast.success(message);
              } else {
                this.$toast.error(message);
              }

              this.$eventBus.$emit('setSelectedIds', []);

              this.$refs.expensesTable.refresh();
            }).catch(err => {
              this.$toast.error(err.response.data.message);
            });
          }
        })
        .catch(err => {
        })
    },
  },
  watch: {
    'form.id'() {
      this.filePath = null;
      if (this.form.file !== null && typeof this.form.file !== 'object') {
        this.filePath = this.form.file;
        this.form.file = null;
      }
    }
  },
  computed: {
    columns() {
      let columns = [];
      if (this.$isAdmin() && this.bulkActionOptions.length) {
        columns.push('checkbox');
      }
      columns.push('expense_date', 'user_id', 'amount', 'file', 'status', 'payment_method', 'category_id', 'project', 'client', 'notes', 'invoice', 'actions');

      if (this.$notAdmin()) {
        columns.pop();
      }
      return columns;
    },
    bulkActionOptions() {
      let actions = ['delete','paid','pending','voided'];

      if (this.$notAdmin()) {
        actions.pop();
      }

      return actions;
    },
  },
}
</script>

<style scoped>

</style>

Spamworldpro Mini