笔记:电子合同

写在前面:本文仅记录了对接e签宝电子合同系统的核心代码,方便以后拿来就用
对接服务:e签宝
功能简要:

笔记:电子合同
本地中间表:esign_template

CREATE TABLE `esign_template` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `user_name` varchar(255) NOT NULL COMMENT '员工user_name',
  `user_info` text NOT NULL COMMENT '生成合同时的员工快照数据',
  `template_id` varchar(255) NOT NULL COMMENT 'e签宝模板id',
  `template_name` varchar(255) NOT NULL COMMENT 'e签宝合同模板名',
  `template_flows` text NOT NULL COMMENT '模板获取的签署区信息',
  `template_data` text NOT NULL COMMENT '模板详细信息',
  `temp_form_value` text NOT NULL COMMENT '生成合同的模板表单数据',
  `temp_doc_id` int(10) unsigned NOT NULL COMMENT 'e签宝模板生成的pdf合同id',
  `file_key` varchar(255) NOT NULL COMMENT 'e签宝模板生成的pdf合同fileKey',
  `pdf_url` varchar(2550) NOT NULL COMMENT 'e签宝pdf合同预览地址',
  `remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注/其他',
  `flow_no` varchar(255) NOT NULL DEFAULT '' COMMENT 'oa的流程编号',
  `status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '合同HRBP确认状态:1表示合同被确认,即将签署',
  `esign_flow_id` varchar(32) NOT NULL DEFAULT '' COMMENT 'e签宝流程Id,status为1将创建e签宝流程,成功返回的流程id',
  `esign_biz_no` varchar(255) NOT NULL DEFAULT '' COMMENT 'e签宝流程创建成功回传的bizNo',
  `esign_url` varchar(2550) NOT NULL DEFAULT '' COMMENT 'e签宝流程签署地址',
  `esign_unique_id` varchar(255) NOT NULL DEFAULT '' COMMENT 'e签宝流程创建成功回传的uniqueId',
  `create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'create_time',
  `update_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'update_time',
  PRIMARY KEY (`id`),
  KEY `idx_username` (`user_name`(32)),
  KEY `idx_flow_no` (`flow_no`(32))
) ENGINE=InnoDB AUTO_INCREMENT=13654 DEFAULT CHARSET=utf8mb4 COMMENT='e签宝模板文件数据';


核心代码:
1.配置config:

<?php
/**
 * e签宝配置文件
 */

return [
    /**
     * e签宝配置文件  | 基本信息
     * 接口公用信息->header:
     *          x-timevale-project-id
     *          x-timevale-signature
     */
    'x_timevale_project_id' => null,
    'x_timevale_signature' => null,
    'operator' => 'oa-php',

    'api-host' => env('ESIGN_API_HOST'),
    'callbackUrl' => env('ESIGN_OA_CALLBACK'),
    'comSignManager' => env('ESIGN_COM_MANAGER'),

    /**
     * e签宝配置文件  |   模板相关
     * 后续可存于数据库,做统一管理
     */
    'template' => [
        /**
         * 合同模板相关:
         *      合同模板编号
         *      合同form表单
         */
        'contract_template' => [
            ['number' => 'CT-HR-0001', 'name' => '劳动合同', 'type' => 1],
        ],

        /**
         * 合同主体印章
         * 正式环境 + 测试环境
         */
        'contract_seal' => env('APP_ENV') === 'production' ? [
            ['contract' => 'xxx公司', 'company_seal' => 'bc3d5fd3-abde-4b12-8299-9fcc738af9c2', 'corporate_seal' => '2e9c0016-b39a-46a5-849b-fc6ee679e8ff'],
        ] : [
            ['contract' => 'xxx公司', 'company_seal' => '02a226cc-d772-4330-89be-b9ac88076ed8', 'corporate_seal' => '6e16dfa7-dc9a-49db-b2ff-fc04736db538'],
        ],

        /**
         * 合同主体基本信息
         */
        'contract_info' => [
            ['contract' => 'xxx公司', 'social_code' => '公司统一社会信用代码', 'legal_person' => '法人', 'address' => '公司地址'],
        ],

        /**
         * e签宝定义字段与oa表字段的关系映射
         * name,instruction源于e签宝
         * source => 来源于数据库还是类文件    |   table => 数据库, class => 类文件, config => 配置值(value)
         */
        'contract_template_all_field' => [
            //来源table的
            ['name' => '工号', 'instruction' => 'job_sn', 'source' => 'table', 'value' => 'users.job_sn', 'desc' => null],
            ['name' => '试用期', 'instruction' => 'try_date', 'source' => 'table', 'value' => 'users.try_date', 'desc' => null],

            //函数处理的
            ['name' => '岗位', 'instruction' => 'job_name', 'source' => 'class', 'value' => 'SpecialFieldValueService.getJobName', 'desc' => null],
            ['name' => '签署时间', 'instruction' => 'esign_time', 'source' => 'class', 'value' => 'SpecialFieldValueService.getESignTime', 'desc' => null],

            //配置值
            ['name' => '配置值', 'instruction' => 'config', 'source' => 'config', 'value' => 'xxxx', 'desc' => null],

        ],
    ],

];

2.核心类ESignUserService、ESignTemplateService、ESignFlowService

<?php
/**
 * e签宝用户相关api
 */

namespace App\Service\EContract;


use App\Service\CurlService;

class ESignUserService
{
    public $host;
    public $operator;

    public $apiMap = [
        'createUser' => '/eSignApi/outerAccountsCreate',
        'updateUser' => '/eSignApi/outerAccountsUpdate',
        'selectUser' => '/eSignApi/outerAccountsQuery',

    ];


    public function __construct()
    {
        $this->host = config('EContract.eSign.api-host');
        $this->operator = config('EContract.eSign.operator');
    }


    /**
     * 创建三方用户
     * name                         |   名字
     * loginMobile,contactsMobile   |   手机号
     * loginEmail,contactsEmail     |   邮箱号
     * licenseType,licenseNumber    |   证件类型 + 证件号
     * uniqueId                     |   唯一标识,英文名
     *
     * @param $name
     * @param $mobile
     * @param $email
     * @param $cardType
     * @param $cardId
     * @param $userName
     * @return mixed
     */
    public function createUser($name, $mobile, $email, $cardType, $cardId, $userName)
    {
        $api = $this->host . $this->apiMap['createUser'];

        $data = [
            'operator' => $this->operator,
            'name' => $name,
            'loginMobile' => $mobile,
            'contactsMobile' => $mobile,
            'loginEmail' => $email,
            'contactsEmail' => $email,
            'licenseType' => $cardType,
            'licenseNumber' => $cardId,
            'uniqueId' => $userName,
        ];

        $rs = CurlService::postJson($api, $data);

        return $rs;
    }

    /**
     * 修改三方用户
     * $accountId                   |   唯一标识
     * name                         |   名字
     * loginMobile,contactsMobile   |   手机号
     * loginEmail,contactsEmail     |   邮箱号
     * licenseType,licenseNumber    |   证件类型 + 证件号
     * uniqueId                     |   唯一标识,英文名
     *
     * @param $accountId
     * @param $name
     * @param $mobile
     * @param $email
     * @param $cardType
     * @param $cardId
     * @param $userName
     * @return mixed
     */
    public function updateUser($accountId, $name, $mobile, $email, $cardType, $cardId, $userName)
    {
        $api = $this->host . $this->apiMap['updateUser'];

        $data = [
            'operator' => $this->operator,
            'accountId' => $accountId,
            'name' => $name,
            'loginMobile' => $mobile,
            'contactsMobile' => $mobile,
            'loginEmail' => $email,
            'contactsEmail' => $email,
            'licenseType' => $cardType,
            'licenseNumber' => $cardId,
            'uniqueId' => $userName,
        ];

        $rs = CurlService::postJson($api, $data);

        return $rs;
    }


    /**
     * 获取e签宝用户信息
     *
     * @param $username
     * @return mixed
     */
    public function getUser($username)
    {
        $api = $this->host . $this->apiMap['selectUser'];

        $data = [
            'operator' => $this->operator,
            'uniqueId' => $username,
        ];

        $rs = CurlService::postJson($api, $data);

        return $rs;
    }


}
<?php
/**
 * e签宝模板,合同生成相关api
 */

namespace App\Service\EContract;


use App\Service\CurlService;

class ESignTemplateService
{

    public $host;
    public $operator;

    public $apiMap = [
        'getTmpInfo' => '/eSignApi/getTemplateInfo',
        'buildPdf' => '/eSignApi/buildTemplateDoc',
        'viewPdf' => '/eSignApi/getPreviewUrl',
    ];


    public function __construct()
    {
        $this->host = config('EContract.eSign.api-host');
        $this->operator = config('EContract.eSign.operator');

    }

    /**
     * 生成合同,返回合同文件信息
     *
     * @param $username   | 合同人
     * @param $contractNo | 合同模板编号
     * @return array      | 根据业务写入中表
     * @throws \App\Exceptions\CustomException
     */
    public function generateContract($username, $contractNo)
    {
        //获取模板信息:form表单
        $api = $this->host . $this->apiMap['getTmpInfo'];
        $data = [
            'operator' => $this->operator,
            'templateId' => $contractNo,
        ];
        $rs = CurlService::postJson($api, $data);
        if (!$rs || $rs['ret'] === false) {
            return ['ok' => false, 'msg' => '获取模板信息失败:' . $rs['message'] . '|templateId:' . $contractNo];
        }

        $template = $rs['data']['template'];
        $templateId = $template['templateId'];
        $templateName = $template['templateName'];
        $templateFormArr = self::getTmpForm($template);
        $templateFormValues = self::getFormValues($username, $templateFormArr);
        $templateFlows = self::getTmpFlow($template);

        //生成pdf合同
        $buildPdfApi = $this->host . $this->apiMap['buildPdf'];
        $pdfData = [
            'operator' => $this->operator,
            'templateFormValues' => $templateFormValues,
            'templateId' => $templateId,
        ];
        $rs1 = CurlService::postJson($buildPdfApi, $pdfData);
        if (!$rs1 || $rs1['ret'] === false) {
            return ['ok' => false, 'msg' => '生成pdf合同失败:' . $rs1['message'] . '|templateId:' . $templateId];
        }
        $tempDocId = $rs1['data']['tempDocId'];
        $fileKey = $rs1['data']['fileKey'];

        //获取生成的pdf合同预览地址
        $viewPdfApi = $this->host . $this->apiMap['viewPdf'];
        $pdfInfoData = [
            'operator' => $this->operator,
            'tempDocId' => $tempDocId,
            'fileKey' => $fileKey,
        ];
        $rs2 = CurlService::postJson($viewPdfApi, $pdfInfoData);
        if (!$rs2 || $rs2['ret'] === false) {
            return ['ok' => false, 'msg' => '获取生成的pdf合同预览地址失败:' . $rs2['message'] . '|tempDocId:' . $tempDocId];
        }
        $pdfUrl = $rs2['data']['url'];

        //todo... 生成合同时的员工快照数据
        $entryInfo = [];
        $arr = [
            'ok' => true,
            'data' => [
                'user_name' => $username,
                'user_info' => $entryInfo,
                'template_id' => $contractNo,
                'template_name' => $templateName,
                'temp_doc_id' => $tempDocId,
                'file_key' => $fileKey,
                'pdf_url' => $pdfUrl,
                'template_flows' => $templateFlows,
                'template_data' => $template,
                'temp_form_value' => $templateFormValues,
            ]
        ];

        return $arr;
    }


    /**
     * 获取模板配置的表单
     *
     * @param $template
     * @return array  => [  145 => "oa_hour_system", 144 => "oa_job_name", 143 => "oa_unit_id"]
     */
    public function getTmpForm($template)
    {
        $templateForms = isset($template['templateForms']) && $template['templateForms'] ? $template['templateForms'] : [];
        if (!$templateForms) {
            return [];
        }
        $templateFormArr = array_column($templateForms, 'instruction', 'formId');
        foreach ($templateFormArr as $key => $val) {
            $templateFormArr[$key] = trim($val);
        }

        return $templateFormArr;
    }

    /**
     * 从oa中获取到相应字段的值
     *
     * @param $username
     * @param $formArr
     * @return array
     * @throws \App\Exceptions\CustomException
     */
    public function getFormValues($username, $formArr)
    {
        $transFieldService = new TransferFieldService();
        $templateFormValues = [];
        foreach ($formArr as $formId => $instruction) {

            $formValue = $transFieldService->getValueByInstruction($username, $instruction);
            array_push($templateFormValues, [
                'formId' => $formId,
                'formValue' => $formValue,
                'instruction' => $instruction,
            ]);
        }

        return $templateFormValues;
    }


    /**
     * 获取签署位置 + 签署时间相关信息
     *
     * @param $template
     * @return array
     */
    public function getTmpFlow($template)
    {
        $templateFlows = isset($template['templateFlows']) ? $template['templateFlows'] : [];
        if (!$templateFlows) {
            return [];
        }

        $flowArr = [];
        foreach ($templateFlows as $key => $val) {
            $flowId = $val['flowId'];
            $flowName = $val['flowName'];
            $positions = isset($val['predefine']['positions']) ? $val['predefine']['positions'] : null;
            $signatureType = isset($val['predefine']['signatureType']) ? $val['predefine']['signatureType'] : null;
            $addSignTime = isset($val['predefine']['addSignTime']) ? $val['predefine']['addSignTime'] : null;

            $pageNo = null;
            $posX = null;
            $posY = null;
            $signTimeInfos = [];
            if ($positions) {
                if ($positions[0]) {
                    $pageNo = $positions[0]['pageNo'];
                    $posX = $positions[0]['posX'];
                    $posY = $positions[0]['posY'];
                    $signTimeInfos = $positions[0]['templateSignTimeInfos'];
                };
            }

            array_push($flowArr, [
                'flowId' => $flowId,
                'flowName' => $flowName,
                'pageNo' => $pageNo,
                'posX' => $posX,
                'posY' => $posY,
                'signatureType' => $signatureType,
                'addSignTime' => $addSignTime,
                'signTimeInfos' => $signTimeInfos,
            ]);
        }

        return $flowArr;
    }


}
<?php
/**
 * e签宝流程相关api
 */

namespace App\Service\EContract;


use App\Exceptions\CustomException;
use App\Service\CurlService;

class ESignFlowService
{
    public $host;
    public $operator;
    public $callbackUrl;

    public $eSignTemplateModel;

    public $apiMap = [
        'createSignFlow' => '/eSignApi/signFlowCreate',
        'getSignFlowDocUrls' => '/eSignApi/getSignFlowDocUrls',
        'cancelSignFlow' => '/eSignApi/flowsCancelCreate',
        'getSignDetail' => '/eSignApi/getSignDetail',
    ];


    public function __construct()
    {
        $this->host = config('EContract.eSign.api-host');
        $this->operator = config('EContract.eSign.operator');
        $this->callbackUrl = config('EContract.eSign.callbackUrl');
        $this->eSignTemplateModel = new ESignTemplateModel();

    }

    public static function getInstance()
    {
        return new self();
    }

    public function getESignSubject()
    {
        return '合同签署流程';
    }

    //流程发起人
    public function getInitiatorUser()
    {
        return 'admin';
    }

    /**
     * 创建签署流程
     *
     * @param      $flowNo
     * @param      $signUser
     * @param bool $auto
     * @return array
     * @throws CustomException
     */
    public function createESignFlow($flowNo, $signUser, $auto = true)
    {
        $api = $this->host . $this->apiMap['createSignFlow'];
        $data = [
            'operator' => $this->operator,
            'subject' => self::getESignSubject(),
            'bizNo' => $flowNo,                     //oa的流程号
            'callbackUrl' => $this->callbackUrl,    //e签宝流程回调通知地址
        ];

        $data['initiatorUniqueId'] = self::getInitiatorUser();
        $data['signDocs'] = self::getSignDocs($flowNo, $signUser);
        $data['signers'] = self::getSigners($flowNo, $signUser, $auto);
        $rs = CurlService::postJson($api, $data);
        if (!$rs || $rs['ret'] === false) {
            throw new CustomException('创建e签宝流程失败:' . $rs['message']);
        }
        $data = $rs['data'];
        $arr = [
            'ok' => true,
            'data' => [
                'esign_flow_id' => $data['signFlowId'],
                'esign_biz_no' => $data['bizNo'],
                'esign_url' => $data['signUrls'][0]['signUrl'],
                'esign_unique_id' => $data['signUrls'][0]['uniqueId'],
            ]
        ];

        return $arr;
    }


    /**
     * 需要签署的合同
     *
     * @param $flowNo   | F120201130043208303
     * @param $signUser | XGM004224
     * @return array
     */
    public function getSignDocs($flowNo, $signUser)
    {
        $where = ['user_name' => $signUser, 'flow_no' => $flowNo];
        $select = ['template_name as docName', 'file_key as docFilekey'];
        $res = $this->eSignTemplateModel->allList($where, $select);

        return $res;
    }

    /**
     * e签宝流程签署节点
     *
     * @param      $flowNo
     * @param      $signUser
     * @param bool $auto
     * @return array
     */
    public function getSigners($flowNo, $signUser, $auto = true)
    {
        $where = ['user_name' => $signUser, 'flow_no' => $flowNo];
        $select = ['user_info', 'template_id', 'template_name as docName', 'file_key as docFilekey', 'template_flows as templateFlows'];
        $res = $this->eSignTemplateModel->allList($where, $select);

        $modifyContract = $modifyInfo->contract_company ?? null;
        //生成合同的员工快照信息
        $userInfo = json_decode($res[0]->user_info, true);
        $oldContract = $userInfo['contract'] ?? null;
        $contract = $modifyContract ? $modifyContract : $oldContract;

        $comSignDocDetails = [];
        $empSignDocDetails = [];
        $oldComSignDocDetails = [];
        foreach ($res as $key => $val) {
            //模板签署区
            $templateFlows = json_decode($val->templateFlows, true);
            list($comSignPos, $empSignPos, $oldComSignPos) = self::getComSignPoint($contract, $templateFlows, $oldContract);

            //公司签署的区域
            if ($comSignPos) {
                $detail = ['docFilekey' => $val->docFilekey, 'signPos' => $comSignPos];
                $comSignDocDetails[] = $detail;
            }
            //原公司签署的区域
            if ($oldComSignPos) {
                $detail = ['docFilekey' => $val->docFilekey, 'signPos' => $oldComSignPos];
                $oldComSignDocDetails[] = $detail;
            }

            //员工签署的区域
            if ($empSignPos) {
                $detail = ['docFilekey' => $val->docFilekey, 'signPos' => $empSignPos];
                $empSignDocDetails[] = $detail;
            }
        }

        $signers = [];
        //公司签 $signers[0]
        if ($comSignDocDetails) {
            $signers[] = [
                'accountType' => 1,                         //内部员工
                'autoSign' => $auto,                         //自动落章
                'signOrder' => 2,                          //签章顺序
                'uniqueId' => self::getComSignManager(),    //公司印章管理员
                'signDocDetails' => $comSignDocDetails,    //签章位置
                'authorizationOrganizeNo' => self::getComSocialCode($contract),     //合同主体统一社会信用code
            ];
        }
        // 转签-公司签 $signers[0]
        if ($oldComSignDocDetails) {
            $signers[] = [
                'accountType' => 1,                         //内部员工
                'autoSign' => $auto,                         //自动落章
                'signOrder' => 2,                          //签章顺序
                'uniqueId' => self::getComSignManager(),    //公司印章管理员
                'signDocDetails' => $oldComSignDocDetails,    //签章位置
                'authorizationOrganizeNo' => self::getComSocialCode($oldContract),     //合同主体统一社会信用code
            ];
        }
        //员工签 $signers[1]
        if ($empSignDocDetails) {
            $signers[] = [
                'accountType' => 2,
                'autoSign' => false,
                'signOrder' => 1,
                'uniqueId' => $signUser,
                'signDocDetails' => $empSignDocDetails,
            ];
        }
        //dd($signers);

        return $signers;
    }

    /**
     * 根据合同主体获取合同主体统一社会信用code
     *
     * @param $contract
     * @return mixed
     */
    public function getComSocialCode($contract)
    {
        $contractInfo = config('EContract.eSign.template.contract_info');
        $res = collect($contractInfo)->where('contract', $contract)->first();
        $socialCode = $res['social_code'];

        return $socialCode;
    }


    /**
     * 获取公司印章管理员
     *
     * @return \Illuminate\Config\Repository|mixed
     */
    public function getComSignManager()
    {
        return config('EContract.eSign.comSignManager');
    }

    /**
     * 是否需要公司盖章
     *
     * @param      $contract    | 合同主体
     * @param      $templateFlows
     * @param null $oldContract | 原合同主体,目前仅转签时使用
     * @return array    二维数组
     */
    public function getComSignPoint($contract, $templateFlows, $oldContract = null)
    {
        $comSignPointArr = [];
        $empSignPointArr = [];
        $oldComSignPointArr = [];
        foreach ($templateFlows as $key => $val) {
            $flowName = $val['flowName'];
            $addSignTime = isset($val['addSignTime']) ? $val['addSignTime'] : false;    //是否有配置签署日期
            $signDateInfos = $addSignTime ? $val['signTimeInfos'] : [];                 //签署日志格式

            if (strpos($flowName, '-公司盖章') !== false) {
                $signPoint = [
                    'sealId' => self::getSealByUserContract($contract, 'company'),   //工章
                    'posPage' => $val['pageNo'],
                    'posX' => $val['posX'],
                    'posY' => $val['posY'],
                    'signType' => 2,                                      //类型:多页
                    'addSignTime' => $addSignTime,
                    'signDateInfos' => $signDateInfos,
                ];
                $comSignPointArr[] = $signPoint;
            } else if (strpos($flowName, '-公司法人章') !== false) {
                $signPoint = [
                    'sealId' => self::getSealByUserContract($contract, 'corporate'),   //法人章
                    'posPage' => $val['pageNo'],
                    'posX' => $val['posX'],
                    'posY' => $val['posY'],
                    'signType' => 2,
                    'addSignTime' => $addSignTime,
                    'signDateInfos' => $signDateInfos,
                ];
                $comSignPointArr[] = $signPoint;
            } else if (strpos($flowName, '-员工签字') !== false) {
                $signPoint = [
                    'sealId' => '',                                     //员工签字为空
                    'posPage' => $val['pageNo'],
                    'posX' => $val['posX'],
                    'posY' => $val['posY'],
                    'signType' => 2,
                    'sealType' => 1,                                    //印章类型;印章类型0:手绘印章1,模板印章,多选用','隔开
                    'addSignTime' => $addSignTime,
                    'signDateInfos' => $signDateInfos,
                ];
                $empSignPointArr[] = $signPoint;
            } else if (strpos($flowName, '-原公司盖章') !== false) {
                $signPoint = [
                    'sealId' => self::getSealByUserContract($oldContract, 'company'),   //工章
                    'posPage' => $val['pageNo'],
                    'posX' => $val['posX'],
                    'posY' => $val['posY'],
                    'signType' => 2,
                    'addSignTime' => $addSignTime,
                    'signDateInfos' => $signDateInfos,
                ];
                $oldComSignPointArr[] = $signPoint;
            }
        }
        //dd($templateFlows, $comSignPointArr);

        return [$comSignPointArr, $empSignPointArr, $oldComSignPointArr];
    }

    /**
     * 根据合同主体获取模板印章id
     *
     * @param $contract => 合同主体字段
     * @param $sealType => 印章类型:company(公司印章), corporate(法人印章)
     * @return string | null
     */
    public function getSealByUserContract($contract, $sealType)
    {
        $sealConfig = config('EContract.eSign.template.contract_seal');
        $sealConfigCol = collect($sealConfig);
        $res = $sealConfigCol->where('contract', $contract)->first();
        if ($sealType === 'company') {
            $sealId = $res['company_seal'];
        } elseif ($sealType === 'corporate') {
            $sealId = $res['corporate_seal'];
        }

        return isset($sealId) ? $sealId : null;
    }

    /**
     * 根据e签宝流程号获取已签署文档的下载地址
     *
     * @param $eSignFlowId
     * @return array
     */
    public function getDownloadDocUrl($eSignFlowId)
    {
        $api = $this->host . $this->apiMap['getSignFlowDocUrls'];
        $data = [
            'operator' => $this->operator,
            'signFlowId' => $eSignFlowId,
        ];
        $rs = CurlService::postJson($api, $data);
        if (!$rs || $rs['ret'] === false) {
            return ['ok' => false, 'msg' => '获取签署文档下载地址失败:' . $rs['message']];
        }
        $data = $rs['data'];
        $arr = [
            'ok' => true,
            'data' => [
                'signDocUrlList' => $data['signDocUrlList'],
            ]
        ];

        return $arr;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * 作废e签宝流程
     *
     * @param $eSignFlowId
     * @param $reason
     * @return array
     */
    public function cancelSignFlow($eSignFlowId, $reason)
    {
        $api = $this->host . $this->apiMap['cancelSignFlow'];
        $data = [
            'operator' => $this->operator,
            'signFlowId' => $eSignFlowId,    //e签宝流程id
            'reason' => $reason,
        ];

        $rs = CurlService::postJson($api, $data);
        $msg = isset($rs['message']) ? $rs['message'] : '无';
        if (!$rs || $rs['ret'] === false) {
            return ['ok' => false, 'msg' => '作废e签宝流程失败:' . $msg];
        }

        return ['ok' => true, 'msg' => '作废e签宝流程成功:' . $msg];
    }


    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //e签宝流程详情
    public function getESignFlowDetail()
    {

    }


}

模板字段解析:TransferFieldService

<?php
/**
 * 获取模板配置字段的值
 */

namespace App\Service\EContract;


use App\Exceptions\CustomException;

class TransferFieldService
{
    /**
     * e签宝模板字段对接特征前缀
     * @var string
     */
    public $eSignFieldPrefix = 'eSign_';

    public $tempAllField;

    public function __construct()
    {
        $this->tempAllField = config('EContract.eSign.template.contract_template_all_field');
    }


    /**
     * 从oa中获取e签宝需要的相关字段值
     * 字段 instruction 配置为空或 instruction 未以‘oa_’开头,也就是配置都错了的情况
     *
     * @param $username
     * @param $instruction
     * @return mixed|string|null
     * @throws CustomException
     */
    public function getValueByInstruction($username, $instruction)
    {
        if (!$instruction || substr($instruction, 0, 3) !== $this->eSignFieldPrefix) {
            throw new CustomException('获取的字段值为空' . $instruction);
        }

        //对 instruction 进行值转换
        $instruction = substr($instruction, 3);
        $tempAllField = $this->tempAllField;

        $value = null;
        $fieldConf = collect($tempAllField)->where('instruction', $instruction)->first();
        if ($fieldConf['source'] === 'table') {
            list($table, $field) = explode('.', $fieldConf['value']);
            $value = $this->getTableField($username, $field, $table);
        } elseif ($fieldConf['source'] === 'class') {
            list($class, $func) = explode('.', $fieldConf['value']);
            //暂时都写到 FieldValueService 里面
            $class = new SpecialFieldValueService();
            $value = call_user_func([$class, $func], $username);
        } elseif ($fieldConf['source'] === 'config') {
            $value = $fieldConf['value'];
        }

        //在oa中值为空时的默认值处理,避免e签宝报错
        if ($value === null) {
            $value = '——';
        }

        return $value;
    }

    /**
     * todo...
     * 获取表字段信息
     *
     * @param $username
     * @param $field
     * @param $table
     * @return mixed|null
     */
    public function getTableField($username, $field, $table)
    {
        $value = '';

        return $value ? $value : null;
    }


}
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 3

这个挺好,买哪个套餐比较划算点呢?

最近有项目要用,还在选型:e签宝、法大大、腾讯电子合同

4周前 评论

契约锁也不错

2周前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!