invoice-update.vue 6.45 KB
<template>
  <Modal v-model="visible" :title="title" @on-ok="ok" @on-cancel="cancel">
    <Form :model="formItem" :label-width="80">
      <FormItem label="订单编号">
        <i-input v-model="formItem.orderCode" readonly></i-input>
      </FormItem>
      <FormItem label="发票类型">
        <RadioGroup v-model="formItem.type">
          <Radio :label="ELECTRONIC">电子发票</Radio>
          <Radio :label="PAPER">纸质发票</Radio>
          <Radio v-if="formItem.status !== UNOPEN" :label="CANCELLED">作废</Radio>
        </RadioGroup>
      </FormItem>
      <template v-if="formItem.status !== CANCELLED">
        <template v-if="formItem.type == ELECTRONIC">
          <FormItem label="上传PDF">
            <drag-file-upload @success="uploadPDFSuccess" @remove="uploadPDFRemove"> </drag-file-upload>
          </FormItem>
        </template>
        <template v-else>
          <RadioGroup v-model="formItem.logisticsSwitch">
            <Radio :label="LOGISTICS_YES">需要物流</Radio>
            <Radio :label="LOGISTICS_NO">不需要物流</Radio>
          </RadioGroup>
          <FormItem v-if="formItem.logisticsSwitch" label="  ">
            <Select v-model="formItem.logisticsCompanyName">
              <Option v-for="(item, idx) in expressList" :key="idx" :value="item.companyName">
                {item.companyName}
              </Option>
            </Select>
            <i-input v-model="formItem.expressNumber" type="text" placeholder="物流单号"></i-input>
          </FormItem>
        </template>
      </template>
    </Form>
    <div slot="footer" class="modal-footer">
      <span v-if="formItem.status !== UNOPEN"><i>*</i>在第三方开票系统冲红或作废后更新保存发票信息</span>
      <Button type="primary" long :loading="inLoading" @click="update">保存</Button>
      <Button long @click="close">关闭</Button>
    </div>
  </Modal>
</template>

<script>
import _ from 'lodash';
import { InvoiceStatusName2Id, InvoiceTypeName2Id, LogisticsTypeName2Id } from '../store/constant';
import InvoiceService from 'services/finance/invoice-service';
import TradeService from 'services/trade/trade-service';
// TODO: move to vuex
let ExpressCompanyList = [];

export default {
  name: 'UpdateInvoice',
  data() {
    return {
      visible: false,
      title: '',
      // constants
      UNOPEN: InvoiceStatusName2Id.UNOPEN,
      CANCELLED: InvoiceStatusName2Id.CANCELLED,
      ...InvoiceTypeName2Id,
      LOGISTICS_NO: LogisticsTypeName2Id.NO,
      LOGISTICS_YES: LogisticsTypeName2Id.YES,
      // api result data
      expressList: ExpressCompanyList,
      formItem: {},
    };
  },
  created() {
    this.invoiceAPI = new InvoiceService();
    this.tradeAPI = new TradeService();
    if (this.expressList.length === 0) {
      this.tradeAPI.allotExpressCompList().then(({ data }) => {
        this.expressList = ExpressCompanyList = data;
      });
    }
  },
  methods: {
    setTitle(invoice) {
      if (invoice.status === InvoiceStatusName2Id.UNOPEN) {
        this.title = '录入发票';
      } else {
        this.title = '发票详情';
      }
    },
    show(invoice) {
      const params = _.pick(invoice, ['shopId', 'orderCode']);
      this.setTitle(invoice);
      this.invoiceAPI.get(params).then(({ data }) => {
        // initial data
        this.invoiceData = data;
        this.formItem = { ...data };
        this.visible = true;
      });
    },
    /**
     * 前端可控制的状态转移
     * Q:
     * 这个作废是什么意思?
     * 选择作废后,下面的 pdf 或物流信息怎么处理
     * 如果发票状态是未开发票,可以先作废吗
     * 选作废后,是不是就不可以编辑当前发票的状态了
     *
     * A:
     * 1.作废就是不提供发票了,之前提供的发票也不展示了
     * 2.删除
     * 3.可以,表示不提供发票
     * 4.可以编辑,作废只是状态之一,不是终点
     *
     * so: rules
     *
     * [1]未开发票->已经开发票
     * [2]退货未处理->退货已经处理
     * [3]作废->已开发票(针对退款额为0)
     * [4]作废->退货已经处理((针对退款额不为0)
     *
     * [5]非作废状态都可作废(*->作废)
     * 退货未处理->作废
     * 退货已经处理->作废
     * 未开发票->作废
     * 已开发票->作废
     * [6] 已开票->已开票, 退货已经处理->退货已经处理
     * return: true: 可以提交, false: 不必提交(当前状态为作废, 选择状态还是作废)
     */
    updateState(invoice) {
      const { status: currentStatus } = this.invoiceData;
      const isCancled = (invoice.status = InvoiceStatusName2Id.CANCELLED);

      if (isCancled) {
        if (currentStatus === isCancled) {
          return false;
        }

        // 作废, 删除关联数据 [5]
        _.assign(invoice, {
          type: InvoiceTypeName2Id.ELECTRONIC,
          pdfUrl: null,
          logisticsSwitch: null,
          logisticsId: null,
          expressNumber: null,
        });
      } else {
        let nextStatus;
        switch (currentStatus) {
          case InvoiceStatusName2Id.UNOPEN:
            nextStatus = InvoiceStatusName2Id.OPNED; // [1]
            break;
          case InvoiceStatusName2Id.REJECT_UNHANDLED:
            nextStatus = InvoiceStatusName2Id.REJECT_HANDLED; // [2]
            break;
          case InvoiceStatusName2Id.CANCELLED:
            if (this.invoiceData.returnAmount === 0) {
              nextStatus = InvoiceStatusName2Id.OPNED; // [3]
            } else {
              nextStatus = InvoiceStatusName2Id.REJECT_HANDLED; // [4]
            }
            break;
          default:
            nextStatus = currentStatus; // [6]
        }
        invoice.status = nextStatus;
      }

      return true;
    },
    update() {
      const params = { ...this.formItem };

      // validate
      // TODO:
      // update status
      if (!this.updateState(params)) {
        this.close(true);
        return;
      }
      this.invoiceAPI
        .update(params)
        .then(() => {
          this.$emit('updated', params);
          this.close();
        })
        .catch(() => {
          this.$methods.warn('更新失败');
        });
    },
    ok() {
      debugger;
    },
    cancel() {
      debugger;
    },
    close(force) {
      if (!force) {
        // dirty check
      }
      this.visible = false;
    },
    uploadPDFSuccess(attach, res) {
      this.formItem.pdfUrl = res.url;
    },
    uploadPDFRemove() {
      this.formItem.pdfUrl = '';
    },
  },
};
</script>