| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600 |
- package com.malk.qiwang.Service.impl;
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONArray;
- import com.alibaba.fastjson.JSONObject;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
- import com.malk.qiwang.Service.QiWangService;
- import com.malk.qiwang.Service.TXYInvoice;
- import com.malk.qiwang.entity.CompanyTitle;
- import com.malk.qiwang.entity.InvoiceLibrary;
- import com.malk.qiwang.mapper.CompanyTitleMapper;
- import com.malk.qiwang.mapper.InvoiceLibraryMapper;
- import com.malk.qiwang.Service.IInvoiceLibraryService;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.malk.qiwang.model.McInvoiceDto;
- import com.malk.server.common.FilePath;
- import com.malk.server.common.McException;
- import com.malk.server.common.McR;
- import com.malk.server.dingtalk.DDR_New;
- import com.malk.service.aliwork.YDClient;
- import com.malk.service.dingtalk.DDClient;
- import com.malk.service.dingtalk.DDClient_Contacts;
- import com.malk.service.dingtalk.DDClient_Workflow;
- import com.malk.utils.*;
- import com.spire.pdf.PdfCompressionLevel;
- import com.spire.pdf.PdfDocument;
- import com.spire.pdf.PdfPageBase;
- import com.spire.pdf.exporting.PdfImageInfo;
- import com.spire.pdf.graphics.PdfBitmap;
- import com.tencentcloudapi.common.exception.TencentCloudSDKException;
- import lombok.SneakyThrows;
- import lombok.extern.slf4j.Slf4j;
- import net.coobird.thumbnailator.Thumbnails;
- import org.apache.commons.lang3.StringUtils;
- import org.apache.poi.hpsf.Decimal;
- import org.apache.poi.util.IOUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.core.io.Resource;
- import org.springframework.core.io.UrlResource;
- import org.springframework.http.HttpEntity;
- import org.springframework.http.HttpHeaders;
- import org.springframework.http.MediaType;
- import org.springframework.http.ResponseEntity;
- import org.springframework.stereotype.Service;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.RequestParam;
- import org.springframework.web.client.RestTemplate;
- import java.io.*;
- import java.math.BigDecimal;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.nio.file.Files;
- import java.nio.file.Path;
- import java.nio.file.Paths;
- import java.time.LocalDate;
- import java.time.LocalDateTime;
- import java.time.format.DateTimeFormatter;
- import java.util.*;
- import java.util.concurrent.CompletableFuture;
- import java.util.stream.Collectors;
- /**
- * <p>
- * 发票库表 服务实现类
- * </p>
- *
- * @author LQY
- * @since 2026-04-27
- */
- @Service
- @Slf4j
- public class InvoiceLibraryServiceImpl extends ServiceImpl<InvoiceLibraryMapper, InvoiceLibrary> implements IInvoiceLibraryService {
- @Autowired
- private QiWangService qiWangService;
- @Autowired
- private DDClient ddClient;
- @Autowired
- private YDClient ydClient;
- @Autowired
- private TXYInvoice txyInvoice;
- @Value("${dingtalk.operator}")
- private String operator;
- @Value("${dingtalk.downloadPath}")
- private String downloadPath;
- @Autowired
- private FilePath filePath;
- @Autowired
- private DDClient_Workflow ddClientWorkflow;
- @Autowired
- private InvoiceLibraryMapper baseMapper;
- @Autowired
- private CompanyTitleMapper companyTitleMapper;
- @Autowired
- private DDClient_Contacts ddClient_contacts;
- private static final String url = "http://47.103.203.2:9092/qiwang/";
- // private static final String url = "http://24120b4f.r39.cpolar.top/qiwang/";
- @Override
- public McR invoiceLibrary(Map map) {
- log.info("接收到的参数: {}", map);
- try {
- String processInstanceId = UtilMap.getString(map, "processInstanceId");
- if (StringUtils.isBlank(processInstanceId)) {
- log.error("processInstanceId为空");
- return McR.error("400", "审批实例ID不能为空");
- }
- // 获取审批实例信息
- String accessToken = ddClient.getAccessToken();
- Map processInstance = ddClientWorkflow.getProcessInstanceId(accessToken, processInstanceId);
- if (processInstance == null) {
- log.error("获取审批实例失败: {}", processInstanceId);
- return McR.error("500", "获取审批实例信息失败");
- }
- String userId = (String) processInstance.get("originatorUserId");
- log.info("审批人ID: {}", userId);
- List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
- if (formComponentValues == null || formComponentValues.isEmpty()) {
- log.warn("表单数据为空");
- return McR.error("400", "表单数据为空");
- }
- // 存储主表的字段值
- String zt = null;
- BigDecimal mainJe = null;
- String bxlb = null;
- String bm = null;
- String fkzhxx = null;
- String fkzh = null;
- String yhqc = null;
- String sfct = null;
- // 遍历收集主表字段值
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- Object value = formComponentValue.get("value");
- if ("DDSelectField_4SITXLYUEO80".equals(id)) {
- zt = value != null ? String.valueOf(value) : "";
- }
- if ("MoneyField_3QZLY8BD3780".equals(id)) {
- if (value instanceof BigDecimal) {
- mainJe = (BigDecimal) value;
- } else if (value != null) {
- try {
- mainJe = new BigDecimal(String.valueOf(value));
- } catch (NumberFormatException e) {
- log.error("金额格式转换失败: {}", value);
- mainJe = BigDecimal.ZERO;
- }
- }
- }
- if ("DDSelectField_1TP75OVCPAAO0".equals(id)) {
- bxlb = value != null ? String.valueOf(value) : "";
- }
- if ("DepartmentField_1RD2SROH579C0".equals(id)) {
- bm = value != null ? String.valueOf(value) : "";
- }
- if ("DDSelectField_11D6S45JKFHS0".equals(id)) {
- fkzhxx = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_1S1VV9PIIQWW0".equals(id)) {
- fkzh = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_ZUVAAH3FIGW0".equals(id)) {
- yhqc = value != null ? String.valueOf(value) : "";
- }
- if ("DDSelectField_DEKPLHARB6O0".equals(id)) {
- sfct = value != null ? String.valueOf(value) : "否";
- }
- }
- // 判断主表状态 - 无发票
- if ("否".equals(zt)) {
- // 保存基础报销记录
- InvoiceLibrary baseInvoice = new InvoiceLibrary();
- baseInvoice.setOaId(processInstanceId);
- baseInvoice.setOaStatus("0");
- baseInvoice.setInvoiceStatus("0");
- baseInvoice.setDep(bm != null ? bm : "");
- baseInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- baseInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- baseInvoice.setCreatedAt(LocalDateTime.now());
- baseInvoice.setUpdatedAt(LocalDateTime.now());
- baseInvoice.setInvoiceCode("");
- baseInvoice.setInvoiceNumber("");
- baseInvoice.setInvoiceType("");
- baseInvoice.setAmount(BigDecimal.ZERO);
- baseInvoice.setTaxAmount(BigDecimal.ZERO);
- baseInvoice.setTotalAmount(BigDecimal.ZERO);
- baseInvoice.setBuyerName("");
- baseInvoice.setBuyerTaxId("");
- baseInvoice.setSellerName("");
- baseInvoice.setSellerTaxId("");
- baseInvoice.setFormName("员工费用报销");
- baseInvoice.setPaySubject(fkzhxx != null ? fkzhxx : "");
- baseInvoice.setPayAccount(fkzh != null ? fkzh : "");
- baseInvoice.setBankName(yhqc != null ? yhqc : "");
- baseInvoice.setIsLongTerm(sfct != null ? sfct : "");
- baseInvoice.setHasInvoice("否");
- baseInvoice.setDetailAmount(null);
- baseInvoice.setSharedTaxAmount(null);
- baseInvoice.setSharedAmount(null);
- baseInvoice.setSharedRate(null);
- baseMapper.insert(baseInvoice);
- addWorkflowComment(processInstanceId, userId, "报销总金额:" + mainJe);
- return McR.success();
- }
- // 判断主表状态 - 有发票
- if ("是".equals(zt)) {
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- if ("TableField_1A1CDMEN8DDS0".equals(id)) {
- String tableFieldValue = String.valueOf(formComponentValue.get("value"));
- log.info("子表数据: {}", tableFieldValue);
- try {
- List<Map> tableRows = (List<Map>) JSONObject.parse(tableFieldValue);
- if (tableRows == null || tableRows.isEmpty()) {
- log.warn("子表数据为空");
- return McR.error("400", "发票明细为空");
- }
- List<Object> allResults = new ArrayList<>();
- List<InvoiceLibrary> invoiceList = new ArrayList<>();
- // 存储第一遍解析的发票数据,避免重复解析
- List<Map<String, Object>> parsedInvoiceDataList = new ArrayList<>();
- // 存储共享发票数据
- List<Map<String, Object>> sharedInvoiceDataList = new ArrayList<>();
- // 用于校验的集合
- List<String> invoiceNumberList = new ArrayList<>();
- Map<String, String> invoiceNumberToFileName = new HashMap<>();
- List<String> invalidBuyerTaxIds = new ArrayList<>();
- // 存储税率值,供共享发票使用
- BigDecimal sharedTaxRate = BigDecimal.ZERO;
- String sharedKind = "";
- // ========== 第一遍遍历:收集并校验所有发票数据 ==========
- for (Map row : tableRows) {
- List<Map> rowValues = (List<Map>) row.get("rowValue");
- String hasInvoice = null;
- String cdbm = null;
- String detailje = null;
- List<Map> attachmentList = null;
- for (Map rowItem : rowValues) {
- String key = String.valueOf(rowItem.get("key"));
- if ("DDSelectField_1ORUK0KIM5D6O".equals(key)) {
- Object value = rowItem.get("value");
- hasInvoice = value != null ? String.valueOf(value) : "";
- }
- if ("DepartmentField_ATSWRJBJ7K00".equals(key)) {
- Object value = rowItem.get("value");
- cdbm = value != null ? String.valueOf(value) : "";
- }
- if ("NumberField_1622XLFLYEWW0".equals(key)) {
- Object value = rowItem.get("value");
- detailje = value != null ? String.valueOf(value) : "";
- }
- if ("DDAttachment_Z02OGR5QL8U8".equals(key)) {
- Object value = rowItem.get("value");
- if (value instanceof List) {
- attachmentList = (List<Map>) value;
- }
- }
- }
- if ("是".equals(hasInvoice) && attachmentList != null && !attachmentList.isEmpty()) {
- for (Map attachment : attachmentList) {
- String fileId = UtilMap.getString(attachment, "fileId");
- String fileType = UtilMap.getString(attachment, "fileType");
- String fileName = UtilMap.getString(attachment, "fileName");
- try {
- String filePath = downloadPath + fileId + "." + fileType;
- downloadDdFile(processInstanceId, fileId, filePath);
- String hz = "qw/files/" + fileId + "." + fileType;
- Map fileMap = new HashMap();
- fileMap.put("url", url + hz);
- fileMap.put("size", new File(filePath).length() / 1024f / 1024f);
- fileMap.put("isPdf", "pdf".equalsIgnoreCase(fileType));
- McR<Object> result = processMixedInvoice(fileMap);
- Object responseData = result.getData();
- // 解析发票数据
- if (responseData != null) {
- String jsonStr = JSONObject.toJSONString(responseData);
- JSONObject jsonObject = JSONObject.parseObject(jsonStr);
- JSONArray resultArray = jsonObject.getJSONArray("result");
- if (resultArray != null && !resultArray.isEmpty()) {
- JSONObject invoice = resultArray.getJSONObject(0);
- String invoiceNumber = invoice.getString("serial") != null ? invoice.getString("serial") : "";
- String buyerTaxId = invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "";
- String buyerName = invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "";
- // 获取税率,供共享发票使用
- Object taxRateObj = invoice.get("taxRate");
- Object kind = invoice.getString("kindName");
- if (taxRateObj != null) {
- String taxRateStr = String.valueOf(taxRateObj);
- String taxRateNum = taxRateStr.replace("%", "").trim();
- sharedKind = kind != null ? String.valueOf(kind) : "";
- sharedTaxRate = new BigDecimal(taxRateNum);
- sharedTaxRate = sharedTaxRate.divide(new BigDecimal("100"), 10, BigDecimal.ROUND_HALF_UP);
- log.info("从有发票中获取税率: 原始={}, 转换后={}", taxRateStr, sharedTaxRate);
- }
- // 保存解析的数据供后续使用
- Map<String, Object> parsedData = new HashMap<>();
- parsedData.put("invoice", invoice);
- parsedData.put("fileId", fileId);
- parsedData.put("fileName", fileName);
- parsedData.put("fileType", fileType);
- parsedData.put("cdbm", cdbm);
- parsedData.put("hasInvoice", hasInvoice);
- parsedData.put("detailje", detailje);
- parsedData.put("responseData", responseData);
- parsedInvoiceDataList.add(parsedData);
- // ========== 校验1:抬头校验 ==========
- if (StringUtils.isNotBlank(buyerName)) {
- CompanyTitle existingTitle = companyTitleMapper.selectByTaxId(buyerName);
- if (existingTitle == null) {
- String errorInfo = String.format("发票: %s, 购买方名称: %s, 税号: %s",
- fileName, buyerName, buyerTaxId);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 税号={} 不存在于抬头库, 文件名={}", buyerTaxId, fileName);
- }
- } else {
- String errorInfo = String.format("发票: %s, 购买方税号为空", fileName);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 购买方税号为空, 文件名={}", fileName);
- }
- // ========== 校验2:发票号重复校验 ==========
- if (StringUtils.isNotBlank(invoiceNumber)) {
- // 检查数据库中是否已存在相同的发票号
- InvoiceLibrary existingInvoice = baseMapper.selectByInvoiceNumber(invoiceNumber);
- if (existingInvoice != null) {
- String errorMsg = String.format("发票号重复: %s (当前文件: %s, 已存在于OA审批单: %s)",
- invoiceNumber, fileName, existingInvoice.getOaId());
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- // 同时检查同一审批单内是否有重复
- if (invoiceNumberList.contains(invoiceNumber)) {
- String errorMsg = String.format("当前审批单内发票号重复: %s (当前文件: %s, 已存在文件: %s)",
- invoiceNumber, fileName, invoiceNumberToFileName.get(invoiceNumber));
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- invoiceNumberList.add(invoiceNumber);
- invoiceNumberToFileName.put(invoiceNumber, fileName);
- }
- }
- }
- } catch (Exception e) {
- log.error("发票解析异常: fileId={}, fileName={}", fileId, fileName, e);
- terminateWorkflow(accessToken, processInstanceId, userId, "发票解析失败: " + e.getMessage());
- return McR.error("400", "发票解析失败: " + e.getMessage());
- }
- }
- } else if ("共享".equals(hasInvoice)) {
- // 收集共享发票数据,待第二遍遍历时保存
- if (detailje != null && StringUtils.isNotBlank(detailje)) {
- Map<String, Object> sharedData = new HashMap<>();
- sharedData.put("detailje", detailje);
- sharedData.put("cdbm", cdbm);
- sharedData.put("hasInvoice", hasInvoice);
- sharedInvoiceDataList.add(sharedData);
- log.info("收集共享发票数据: 金额={}, 成本部门={}", detailje, cdbm);
- }
- }
- }
- // ========== 抬头校验失败处理 ==========
- if (!invalidBuyerTaxIds.isEmpty()) {
- String errorMsg = "发票抬头有误,以下发票的购买方税号不在公司抬头库中:\n" + String.join("\n", invalidBuyerTaxIds);
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- BigDecimal totalAmount = BigDecimal.ZERO;
- // ========== 第二遍遍历:保存发票数据(校验通过后) ==========
- // 1. 保存普通发票数据
- for (Map<String, Object> parsedData : parsedInvoiceDataList) {
- JSONObject invoice = (JSONObject) parsedData.get("invoice");
- Object responseData = parsedData.get("responseData");
- String cdbm = (String) parsedData.get("cdbm");
- String hasInvoice = (String) parsedData.get("hasInvoice");
- String detailje = (String) parsedData.get("detailje"); // 修改为 String 类型
- allResults.add(responseData);
- // 汇总 amount
- BigDecimal amount = invoice.getBigDecimal("amount");
- if (amount != null) {
- totalAmount = totalAmount.add(amount);
- }
- // 构建InvoiceLibrary对象
- InvoiceLibrary invoiceLibrary = new InvoiceLibrary();
- invoiceLibrary.setOaId(processInstanceId);
- invoiceLibrary.setInvoiceCode(invoice.getString("code") != null ? invoice.getString("code") : "");
- invoiceLibrary.setInvoiceNumber(invoice.getString("serial") != null ? invoice.getString("serial") : "");
- invoiceLibrary.setInvoiceType(invoice.getString("kindName") != null ? invoice.getString("kindName") : "");
- String date = invoice.getString("date");
- if (StringUtils.isNotBlank(date)) {
- try {
- invoiceLibrary.setInvoiceDate(LocalDate.parse(date.trim()));
- } catch (Exception e) {
- log.warn("日期解析失败: {}", date);
- }
- }
- invoiceLibrary.setAmount(invoice.getBigDecimal("excludingTax") != null ? invoice.getBigDecimal("excludingTax") : BigDecimal.ZERO);
- invoiceLibrary.setTaxAmount(invoice.getBigDecimal("tax") != null ? invoice.getBigDecimal("tax") : BigDecimal.ZERO);
- invoiceLibrary.setTotalAmount(invoice.getBigDecimal("amount") != null ? invoice.getBigDecimal("amount") : BigDecimal.ZERO);
- invoiceLibrary.setBuyerName(invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "");
- invoiceLibrary.setBuyerTaxId(invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "");
- invoiceLibrary.setSellerName(invoice.getString("sellerName") != null ? invoice.getString("sellerName") : "");
- invoiceLibrary.setSellerTaxId(invoice.getString("sellerTaxId") != null ? invoice.getString("sellerTaxId") : "");
- invoiceLibrary.setOaStatus("0");
- invoiceLibrary.setFormName("员工费用报销");
- invoiceLibrary.setPaySubject(fkzhxx != null ? fkzhxx : "");
- invoiceLibrary.setPayAccount(fkzh != null ? fkzh : "");
- invoiceLibrary.setBankName(yhqc != null ? yhqc : "");
- invoiceLibrary.setIsLongTerm(sfct != null ? sfct : "");
- invoiceLibrary.setInvoiceStatus("0");
- invoiceLibrary.setHasInvoice(hasInvoice);
- // 处理 detailAmount,将 String 转换为 BigDecimal
- if (detailje != null && StringUtils.isNotBlank(detailje)) {
- try {
- invoiceLibrary.setDetailAmount(new BigDecimal(detailje));
- } catch (NumberFormatException e) {
- log.error("detailJe格式转换失败: {}", detailje);
- invoiceLibrary.setDetailAmount(null);
- }
- } else {
- invoiceLibrary.setDetailAmount(null);
- }
- // 普通发票不涉及共享字段,设置为 null
- invoiceLibrary.setSharedTaxAmount(null);
- invoiceLibrary.setSharedAmount(null);
- invoiceLibrary.setSharedRate(null);
- invoiceLibrary.setAccountTitle(bxlb != null ? bxlb : "");
- invoiceLibrary.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- invoiceLibrary.setCreatedAt(LocalDateTime.now());
- invoiceLibrary.setUpdatedAt(LocalDateTime.now());
- // 设置成本部门
- if (cdbm != null && StringUtils.isNotBlank(cdbm)) {
- invoiceLibrary.setDep(cdbm);
- } else {
- invoiceLibrary.setDep(bm != null ? bm : "");
- }
- invoiceList.add(invoiceLibrary);
- }
- for (Map<String, Object> sharedData : sharedInvoiceDataList) {
- String detailje = (String) sharedData.get("detailje");
- String cdbm = (String) sharedData.get("cdbm");
- String hasInvoice = (String) sharedData.get("hasInvoice");
- try {
- BigDecimal detailAmount = new BigDecimal(detailje);
- // 使用从普通发票中解析到的税率
- BigDecimal ocrTaxRate = sharedTaxRate;
- if (ocrTaxRate.compareTo(BigDecimal.ZERO) == 0) {
- log.warn("共享发票税率未获取到,使用默认税率0,金额={}", detailAmount);
- }
- // 计算金额: 含税金额 / (1 + 税率) = 税额
- BigDecimal divisor = BigDecimal.ONE.add(ocrTaxRate);
- BigDecimal sharedTaxAmount = detailAmount.divide(divisor, 2, BigDecimal.ROUND_HALF_UP);
- BigDecimal sharedAmount = detailAmount.subtract(sharedTaxAmount);
- BigDecimal sharedRate = ocrTaxRate; // 这是小数形式的税率,如 0.09
- log.info("共享发票计算: 含税金额={}, 税率={}%, 不含税金额={}, 税额={}",
- detailAmount, ocrTaxRate.multiply(new BigDecimal("100")),
- sharedAmount, sharedTaxAmount);
- // 保存共享发票数据
- InvoiceLibrary sharedInvoice = new InvoiceLibrary();
- sharedInvoice.setOaId(processInstanceId);
- sharedInvoice.setOaStatus("0");
- sharedInvoice.setInvoiceStatus("0");
- sharedInvoice.setDep(cdbm != null && StringUtils.isNotBlank(cdbm) ? cdbm : (bm != null ? bm : ""));
- sharedInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- sharedInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- sharedInvoice.setAmount(null);
- sharedInvoice.setTaxAmount(null);
- sharedInvoice.setTotalAmount(null); // 共享发票不设置总金额
- sharedInvoice.setFormName("员工费用报销");
- sharedInvoice.setPaySubject(fkzhxx != null ? fkzhxx : "");
- sharedInvoice.setPayAccount(fkzh != null ? fkzh : "");
- sharedInvoice.setBankName(yhqc != null ? yhqc : "");
- sharedInvoice.setIsLongTerm(sfct != null ? sfct : "");
- sharedInvoice.setHasInvoice(hasInvoice);
- sharedInvoice.setDetailAmount(detailAmount);
- // 共享发票字段设置值 - 修正:存储数字而不是带百分号的字符串
- sharedInvoice.setSharedTaxAmount(sharedAmount);
- sharedInvoice.setSharedAmount(sharedTaxAmount);
- sharedInvoice.setSharedRate(String.valueOf(sharedRate)); // 直接存储小数,如 0.09
- sharedInvoice.setCreatedAt(LocalDateTime.now());
- sharedInvoice.setUpdatedAt(LocalDateTime.now());
- sharedInvoice.setInvoiceCode("");
- sharedInvoice.setInvoiceNumber("");
- sharedInvoice.setInvoiceType(sharedKind);
- sharedInvoice.setBuyerName("");
- sharedInvoice.setBuyerTaxId("");
- sharedInvoice.setSellerName("");
- sharedInvoice.setSellerTaxId("");
- invoiceList.add(sharedInvoice);
- log.info("成功保存共享发票记录,成本部门: {}", cdbm);
- } catch (NumberFormatException e) {
- log.error("共享发票金额格式转换失败: detailje={}", detailje, e);
- } catch (Exception e) {
- log.error("共享发票处理失败", e);
- }
- }
- // 保存发票记录
- if (!invoiceList.isEmpty()) {
- for (InvoiceLibrary invoice : invoiceList) {
- baseMapper.insert(invoice);
- }
- log.info("成功保存 {} 条发票记录(普通发票: {}, 共享发票: {})",
- invoiceList.size(), parsedInvoiceDataList.size(), sharedInvoiceDataList.size());
- }
- addWorkflowComment1(processInstanceId, userId, totalAmount);
- return McR.success(allResults);
- } catch (Exception e) {
- log.error("解析子表数据失败", e);
- return McR.error("300", "解析数据失败: " + e.getMessage());
- }
- }
- }
- }
- return McR.success();
- } catch (Exception e) {
- log.error("处理审批实例失败", e);
- return McR.error("500", "系统处理失败: " + e.getMessage());
- }
- }
- /**
- * 终止钉钉审批流程
- *
- * @param accessToken 钉钉accessToken
- * @param processInstanceId 审批实例ID
- * @param operatingUserId 操作人用户ID(通常是发起人ID)
- * @param remark 终止原因备注
- */
- private void terminateWorkflow(String accessToken, String processInstanceId, String operatingUserId, String remark) {
- // 异步延迟15秒后执行终止
- CompletableFuture.runAsync(() -> {
- try {
- log.info("延迟15秒后开始终止审批流程: processInstanceId={}, remark={}", processInstanceId, remark);
- Thread.sleep(15000);
- // 实际执行终止操作
- doTerminateWorkflow(accessToken, processInstanceId, operatingUserId, remark);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.error("延迟终止流程被中断: processInstanceId={}", processInstanceId, e);
- } catch (Exception e) {
- log.error("异步执行终止流程异常: processInstanceId={}", processInstanceId, e);
- }
- });
- }
- /**
- * 实际执行钉钉审批流程终止
- */
- private void doTerminateWorkflow(String accessToken, String processInstanceId, String operatingUserId, String remark) {
- try {
- log.info("开始调用钉钉API终止审批流程: processInstanceId={}", processInstanceId);
- // 构建请求URL
- String url = "https://api.dingtalk.com/v1.0/workflow/processInstances/terminate";
- // 构建请求头
- HttpHeaders headers = new HttpHeaders();
- headers.setContentType(MediaType.APPLICATION_JSON);
- headers.set("x-acs-dingtalk-access-token", accessToken);
- // 构建请求体
- Map<String, Object> requestBody = new HashMap<>();
- requestBody.put("processInstanceId", processInstanceId);
- requestBody.put("isSystem", true); // 系统调用终止
- requestBody.put("remark", remark);
- requestBody.put("operatingUserId", operatingUserId);
- log.info("钉钉终止请求参数: {}", requestBody);
- // 发送POST请求
- HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
- RestTemplate restTemplate = new RestTemplate();
- ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
- if (response.getStatusCode().is2xxSuccessful()) {
- log.info("审批流程终止成功: processInstanceId={}, response={}", processInstanceId, response.getBody());
- } else {
- log.error("审批流程终止失败: processInstanceId={}, statusCode={}, response={}",
- processInstanceId, response.getStatusCode(), response.getBody());
- }
- } catch (Exception e) {
- log.error("调用钉钉终止流程接口异常: processInstanceId={}, error={}", processInstanceId, e.getMessage(), e);
- }
- }
- @Override
- public void updateOaStatusByOaId(Map map) {
- try {
- String oaId = UtilMap.getString(map, "oaId");
- // 创建更新条件
- LambdaUpdateWrapper<InvoiceLibrary> updateWrapper = new LambdaUpdateWrapper<>();
- updateWrapper.eq(InvoiceLibrary::getOaId, oaId)
- .set(InvoiceLibrary::getOaStatus, "1")
- .set(InvoiceLibrary::getUpdatedAt, LocalDateTime.now());
- int updateCount = baseMapper.update(null, updateWrapper);
- if (updateCount > 0) {
- log.info("更新成功: 共更新{}条记录", updateCount);
- } else {
- log.warn("未找到符合条件的记录: oaId={}", oaId);
- }
- } catch (Exception e) {
- throw new RuntimeException("更新OA状态失败", e);
- }
- }
- @Override
- public McR invoiceLibrarys(Map map) {
- log.info("接收到的参数: {}", map);
- try {
- String processInstanceId = UtilMap.getString(map, "processInstanceId");
- if (StringUtils.isBlank(processInstanceId)) {
- log.error("processInstanceId为空");
- return McR.error("400", "审批实例ID不能为空");
- }
- // 获取审批实例信息
- String accessToken = ddClient.getAccessToken();
- Map processInstance = ddClientWorkflow.getProcessInstanceId(accessToken, processInstanceId);
- if (processInstance == null) {
- log.error("获取审批实例失败: {}", processInstanceId);
- return McR.error("500", "获取审批实例信息失败");
- }
- String userId = (String) processInstance.get("originatorUserId");
- log.info("审批人ID: {}", userId);
- List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
- if (formComponentValues == null || formComponentValues.isEmpty()) {
- log.warn("表单数据为空");
- return McR.error("400", "表单数据为空");
- }
- // 存储主表的字段值
- String zt = null;
- BigDecimal mainJe = null;
- String bxlb = null;
- String bm = null;
- // 遍历收集主表字段值
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- Object value = formComponentValue.get("value");
- if ("DDSelectField_4SITXLYUEO80".equals(id)) {
- zt = value != null ? String.valueOf(value) : "";
- }
- if ("MoneyField_3QZLY8BD3780".equals(id)) {
- if (value instanceof BigDecimal) {
- mainJe = (BigDecimal) value;
- } else if (value != null) {
- try {
- mainJe = new BigDecimal(String.valueOf(value));
- } catch (NumberFormatException e) {
- log.error("金额格式转换失败: {}", value);
- mainJe = BigDecimal.ZERO;
- }
- }
- }
- if ("DDSelectField_1TP75OVCPAAO0".equals(id)) {
- bxlb = value != null ? String.valueOf(value) : "";
- }
- if ("DepartmentField_OKBSJN0MD6O0".equals(id)) {
- bm = value != null ? String.valueOf(value) : "";
- }
- }
- // 判断主表状态 - 无发票
- if ("否".equals(zt)) {
- Map<String, Object> result = new HashMap<>();
- result.put("je", mainJe);
- result.put("status", "否");
- result.put("message", "无发票报销");
- // 保存基础报销记录
- InvoiceLibrary baseInvoice = new InvoiceLibrary();
- baseInvoice.setOaId(processInstanceId);
- baseInvoice.setOaStatus("0");
- baseInvoice.setInvoiceStatus("0");
- baseInvoice.setDep(bm != null ? bm : "");
- baseInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- baseInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- baseInvoice.setCreatedAt(LocalDateTime.now());
- baseInvoice.setUpdatedAt(LocalDateTime.now());
- baseInvoice.setInvoiceCode("");
- baseInvoice.setInvoiceNumber("");
- baseInvoice.setInvoiceType("");
- baseInvoice.setAmount(BigDecimal.ZERO);
- baseInvoice.setTaxAmount(BigDecimal.ZERO);
- baseInvoice.setTotalAmount(BigDecimal.ZERO);
- baseInvoice.setBuyerName("");
- baseInvoice.setBuyerTaxId("");
- baseInvoice.setSellerName("");
- baseInvoice.setSellerTaxId("");
- baseMapper.insert(baseInvoice);
- addWorkflowComment(processInstanceId, userId, result);
- return McR.success(result);
- }
- // 判断主表状态 - 有发票
- if ("是".equals(zt)) {
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- if ("TableField_1A1CDMEN8DDS0".equals(id)) {
- String tableFieldValue = String.valueOf(formComponentValue.get("value"));
- log.info("子表数据: {}", tableFieldValue);
- try {
- List<Map> tableRows = (List<Map>) JSONObject.parse(tableFieldValue);
- if (tableRows == null || tableRows.isEmpty()) {
- log.warn("子表数据为空");
- return McR.error("400", "发票明细为空");
- }
- List<Object> allResults = new ArrayList<>();
- List<InvoiceLibrary> invoiceList = new ArrayList<>();
- for (Map row : tableRows) {
- List<Map> rowValues = (List<Map>) row.get("rowValue");
- String hasInvoice = null;
- List<Map> attachmentList = null;
- for (Map rowItem : rowValues) {
- String key = String.valueOf(rowItem.get("key"));
- if ("DDSelectField_1ORUK0KIM5D6O".equals(key)) {
- Object value = rowItem.get("value");
- hasInvoice = value != null ? String.valueOf(value) : "";
- }
- if ("DDAttachment_Z02OGR5QL8U8".equals(key)) {
- Object value = rowItem.get("value");
- if (value instanceof List) {
- attachmentList = (List<Map>) value;
- }
- }
- }
- if ("是".equals(hasInvoice) && attachmentList != null && !attachmentList.isEmpty()) {
- for (Map attachment : attachmentList) {
- String fileId = UtilMap.getString(attachment, "fileId");
- String fileType = UtilMap.getString(attachment, "fileType");
- String fileName = UtilMap.getString(attachment, "fileName");
- log.info("处理发票: fileName={}, fileId={}", fileName, fileId);
- try {
- String filePath = downloadPath + fileId + "." + fileType;
- downloadDdFile(processInstanceId, fileId, filePath);
- String hz = "qw/files/" + fileId + "." + fileType;
- Map fileMap = new HashMap();
- fileMap.put("url", url + hz);
- fileMap.put("size", new File(filePath).length() / 1024f / 1024f);
- fileMap.put("isPdf", "pdf".equalsIgnoreCase(fileType));
- McR<Object> result = processMixedInvoice(fileMap);
- Object responseData = result.getData();
- allResults.add(responseData);
- // 解析发票数据 - responseData 是对象,不是数组
- if (responseData != null) {
- try {
- String jsonStr = JSONObject.toJSONString(responseData);
- JSONObject jsonObject = JSONObject.parseObject(jsonStr);
- // 获取 result 数组
- JSONArray resultArray = jsonObject.getJSONArray("result");
- if (resultArray != null && !resultArray.isEmpty()) {
- JSONObject invoice = resultArray.getJSONObject(0);
- InvoiceLibrary invoiceLibrary = new InvoiceLibrary();
- invoiceLibrary.setOaId(processInstanceId);
- invoiceLibrary.setInvoiceCode(invoice.getString("code") != null ? invoice.getString("code") : "");
- invoiceLibrary.setInvoiceNumber(invoice.getString("serial") != null ? invoice.getString("serial") : "");
- invoiceLibrary.setInvoiceType(invoice.getString("kindName") != null ? invoice.getString("kindName") : "");
- String date = invoice.getString("date");
- if (StringUtils.isNotBlank(date)) {
- try {
- invoiceLibrary.setInvoiceDate(LocalDate.parse(date.trim()));
- } catch (Exception e) {
- log.warn("日期解析失败: {}", date);
- }
- }
- invoiceLibrary.setAmount(invoice.getBigDecimal("excludingTax") != null ? invoice.getBigDecimal("excludingTax") : BigDecimal.ZERO);
- invoiceLibrary.setTaxAmount(invoice.getBigDecimal("tax") != null ? invoice.getBigDecimal("tax") : BigDecimal.ZERO);
- invoiceLibrary.setTotalAmount(invoice.getBigDecimal("amount") != null ? invoice.getBigDecimal("amount") : BigDecimal.ZERO);
- invoiceLibrary.setBuyerName(invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "");
- invoiceLibrary.setBuyerTaxId(invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "");
- invoiceLibrary.setSellerName(invoice.getString("sellerName") != null ? invoice.getString("sellerName") : "");
- invoiceLibrary.setSellerTaxId(invoice.getString("sellerTaxId") != null ? invoice.getString("sellerTaxId") : "");
- invoiceLibrary.setOaStatus("0");
- invoiceLibrary.setInvoiceStatus("0");
- invoiceLibrary.setDep(bm != null ? bm : "");
- invoiceLibrary.setAccountTitle(bxlb != null ? bxlb : "");
- invoiceLibrary.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- invoiceLibrary.setCreatedAt(LocalDateTime.now());
- invoiceLibrary.setUpdatedAt(LocalDateTime.now());
- invoiceList.add(invoiceLibrary);
- }
- } catch (Exception e) {
- log.error("解析发票数据失败", e);
- }
- }
- } catch (Exception e) {
- log.error("处理发票失败: fileId={}, fileName={}", fileId, fileName, e);
- }
- }
- }
- }
- if (!invoiceList.isEmpty()) {
- for (InvoiceLibrary invoice : invoiceList) {
- baseMapper.insert(invoice);
- }
- log.info("成功保存 {} 条发票记录", invoiceList.size());
- }
- addWorkflowComment(processInstanceId, userId, allResults);
- return McR.success(allResults);
- } catch (Exception e) {
- log.error("解析子表数据失败", e);
- return McR.error("300", "解析数据失败: " + e.getMessage());
- }
- }
- }
- }
- return McR.success();
- } catch (Exception e) {
- log.error("处理审批实例失败", e);
- return McR.error("500", "系统处理失败: " + e.getMessage());
- }
- }
- @Override
- public McR deleteAllByOaId(String oaId) {
- try {
- // 创建删除条件
- LambdaQueryWrapper<InvoiceLibrary> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(InvoiceLibrary::getOaId, oaId);
- // 执行删除
- int deleteCount = baseMapper.delete(queryWrapper);
- if (deleteCount > 0) {
- return McR.success("删除成功,共删除 " + deleteCount + " 条记录");
- } else {
- return McR.error("404", "未找到 oa_id 为 " + oaId + " 的记录");
- }
- } catch (Exception e) {
- log.error("删除失败", e);
- return McR.error("500", "删除失败: " + e.getMessage());
- }
- }
- @Override
- public McR invoiceLibrary1(Map map) {
- log.info("接收到的参数: {}", map);
- try {
- String processInstanceId = UtilMap.getString(map, "processInstanceId");
- if (StringUtils.isBlank(processInstanceId)) {
- log.error("processInstanceId为空");
- return McR.error("400", "审批实例ID不能为空");
- }
- // 获取审批实例信息
- String accessToken = ddClient.getAccessToken();
- Map processInstance = ddClientWorkflow.getProcessInstanceId(accessToken, processInstanceId);
- if (processInstance == null) {
- log.error("获取审批实例失败: {}", processInstanceId);
- return McR.error("500", "获取审批实例信息失败");
- }
- String userId = (String) processInstance.get("originatorUserId");
- log.info("审批人ID: {}", userId);
- List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
- if (formComponentValues == null || formComponentValues.isEmpty()) {
- log.warn("表单数据为空");
- return McR.error("400", "表单数据为空");
- }
- // 存储主表的字段值
- String zt = null;
- BigDecimal mainJe = null;
- String bxlb = null;
- String bm = null;
- String fkzhxx = null;
- String fkzh = null;
- String yhqc = null;
- String sfct = null;
- // 遍历收集主表字段值
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- Object value = formComponentValue.get("value");
- if ("DDSelectField_4TXFWTKFF7K0".equals(id)) {
- zt = value != null ? String.valueOf(value) : "";
- }
- if ("MoneyField_1FVEBDQBSQ680".equals(id)) {
- if (value instanceof BigDecimal) {
- mainJe = (BigDecimal) value;
- } else if (value != null) {
- try {
- mainJe = new BigDecimal(String.valueOf(value));
- } catch (NumberFormatException e) {
- log.error("金额格式转换失败: {}", value);
- mainJe = BigDecimal.ZERO;
- }
- }
- }
- if ("DDSelectField_YLLB7AD1ATS0".equals(id)) {
- bxlb = value != null ? String.valueOf(value) : "";
- }
- if ("DepartmentField_RF93A6VHA9C0".equals(id)) {
- bm = value != null ? String.valueOf(value) : "";
- }
- if ("DDSelectField_23RVAEKUM5UO0".equals(id)) {
- fkzhxx = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_1TE3AOHRMD4W0".equals(id)) {
- fkzh = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_EN2MDZIMUTK0".equals(id)) {
- yhqc = value != null ? String.valueOf(value) : "";
- }
- if ("DDSelectField_P2EFYKN5ALC0".equals(id)) {
- sfct = value != null ? String.valueOf(value) : "否";
- }
- }
- // 判断主表状态 - 无发票
- if ("否".equals(zt)) {
- // 保存基础报销记录
- InvoiceLibrary baseInvoice = new InvoiceLibrary();
- baseInvoice.setOaId(processInstanceId);
- baseInvoice.setOaStatus("0");
- baseInvoice.setInvoiceStatus("0");
- baseInvoice.setDep(bm != null ? bm : "");
- baseInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- baseInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- baseInvoice.setCreatedAt(LocalDateTime.now());
- baseInvoice.setUpdatedAt(LocalDateTime.now());
- baseInvoice.setInvoiceCode("");
- baseInvoice.setInvoiceNumber("");
- baseInvoice.setInvoiceType("");
- baseInvoice.setAmount(BigDecimal.ZERO);
- baseInvoice.setTaxAmount(BigDecimal.ZERO);
- baseInvoice.setTotalAmount(BigDecimal.ZERO);
- baseInvoice.setBuyerName("");
- baseInvoice.setBuyerTaxId("");
- baseInvoice.setSellerName("");
- baseInvoice.setSellerTaxId("");
- baseInvoice.setFormName("付款申请");
- baseInvoice.setPaySubject(fkzhxx != null ? fkzhxx : "");
- baseInvoice.setPayAccount(fkzh != null ? fkzh : "");
- baseInvoice.setBankName(yhqc != null ? yhqc : "");
- baseInvoice.setIsLongTerm(sfct != null ? sfct : "");
- baseInvoice.setHasInvoice("否");
- baseInvoice.setDetailAmount(null);
- baseInvoice.setSharedTaxAmount(null);
- baseInvoice.setSharedAmount(null);
- baseInvoice.setSharedRate(null);
- baseMapper.insert(baseInvoice);
- addWorkflowComment(processInstanceId, userId, "报销总金额:" + mainJe);
- return McR.success();
- }
- // 判断主表状态 - 有发票
- if ("是".equals(zt)) {
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- if ("TableField_1VKP90DW7WKG0".equals(id)) {
- String tableFieldValue = String.valueOf(formComponentValue.get("value"));
- log.info("子表数据: {}", tableFieldValue);
- try {
- List<Map> tableRows = (List<Map>) JSONObject.parse(tableFieldValue);
- if (tableRows == null || tableRows.isEmpty()) {
- log.warn("子表数据为空");
- return McR.error("400", "发票明细为空");
- }
- List<Object> allResults = new ArrayList<>();
- List<InvoiceLibrary> invoiceList = new ArrayList<>();
- // 存储第一遍解析的发票数据,避免重复解析
- List<Map<String, Object>> parsedInvoiceDataList = new ArrayList<>();
- // 存储共享发票数据
- List<Map<String, Object>> sharedInvoiceDataList = new ArrayList<>();
- // 用于校验的集合
- List<String> invoiceNumberList = new ArrayList<>();
- Map<String, String> invoiceNumberToFileName = new HashMap<>();
- List<String> invalidBuyerTaxIds = new ArrayList<>();
- // 存储税率值,供共享发票使用
- BigDecimal sharedTaxRate = BigDecimal.ZERO;
- String sharedKind = "";
- // ========== 第一遍遍历:收集并校验所有发票数据 ==========
- for (Map row : tableRows) {
- List<Map> rowValues = (List<Map>) row.get("rowValue");
- String hasInvoice = null;
- String cdbm = null;
- String detailje = null;
- List<Map> attachmentList = null;
- for (Map rowItem : rowValues) {
- String key = String.valueOf(rowItem.get("key"));
- if ("DDSelectField_20ZGDOIRHB400".equals(key)) {
- Object value = rowItem.get("value");
- hasInvoice = value != null ? String.valueOf(value) : "";
- }
- if ("DepartmentField_1VQ3M98PC7SW0".equals(key)) {
- Object value = rowItem.get("value");
- cdbm = value != null ? String.valueOf(value) : "";
- }
- if ("NumberField_BLX4BRW8GEW0".equals(key)) {
- Object value = rowItem.get("value");
- detailje = value != null ? String.valueOf(value) : "";
- }
- if ("DDAttachment_1YQ3DD7BH4BK0".equals(key)) {
- Object value = rowItem.get("value");
- if (value instanceof List) {
- attachmentList = (List<Map>) value;
- }
- }
- }
- if ("是".equals(hasInvoice) && attachmentList != null && !attachmentList.isEmpty()) {
- for (Map attachment : attachmentList) {
- String fileId = UtilMap.getString(attachment, "fileId");
- String fileType = UtilMap.getString(attachment, "fileType");
- String fileName = UtilMap.getString(attachment, "fileName");
- try {
- String filePath = downloadPath + fileId + "." + fileType;
- downloadDdFile(processInstanceId, fileId, filePath);
- String hz = "qw/files/" + fileId + "." + fileType;
- Map fileMap = new HashMap();
- fileMap.put("url", url + hz);
- fileMap.put("size", new File(filePath).length() / 1024f / 1024f);
- fileMap.put("isPdf", "pdf".equalsIgnoreCase(fileType));
- McR<Object> result = processMixedInvoice(fileMap);
- Object responseData = result.getData();
- // 解析发票数据
- if (responseData != null) {
- String jsonStr = JSONObject.toJSONString(responseData);
- JSONObject jsonObject = JSONObject.parseObject(jsonStr);
- JSONArray resultArray = jsonObject.getJSONArray("result");
- if (resultArray != null && !resultArray.isEmpty()) {
- JSONObject invoice = resultArray.getJSONObject(0);
- String invoiceNumber = invoice.getString("serial") != null ? invoice.getString("serial") : "";
- String buyerTaxId = invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "";
- String buyerName = invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "";
- // 获取税率,供共享发票使用
- Object taxRateObj = invoice.get("taxRate");
- Object kind = invoice.getString("kindName");
- System.out.println("qqq"+taxRateObj);
- System.out.println("qqq"+kind);
- if (taxRateObj != null) {
- String taxRateStr = String.valueOf(taxRateObj);
- String taxRateNum = taxRateStr.replace("%", "").trim();
- sharedKind = kind != null ? String.valueOf(kind) : "";
- sharedTaxRate = new BigDecimal(taxRateNum);
- sharedTaxRate = sharedTaxRate.divide(new BigDecimal("100"), 10, BigDecimal.ROUND_HALF_UP);
- log.info("从有发票中获取税率: 原始={}, 转换后={}", taxRateStr, sharedTaxRate);
- }
- // 保存解析的数据供后续使用
- Map<String, Object> parsedData = new HashMap<>();
- parsedData.put("invoice", invoice);
- parsedData.put("fileId", fileId);
- parsedData.put("fileName", fileName);
- parsedData.put("fileType", fileType);
- parsedData.put("cdbm", cdbm);
- parsedData.put("hasInvoice", hasInvoice);
- parsedData.put("detailje", detailje);
- parsedData.put("responseData", responseData);
- parsedInvoiceDataList.add(parsedData);
- // ========== 校验1:抬头校验 ==========
- if (StringUtils.isNotBlank(buyerName)) {
- CompanyTitle existingTitle = companyTitleMapper.selectByTaxId(buyerName);
- if (existingTitle == null) {
- String errorInfo = String.format("发票: %s, 购买方名称: %s, 税号: %s",
- fileName, buyerName, buyerTaxId);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 税号={} 不存在于抬头库, 文件名={}", buyerTaxId, fileName);
- }
- } else {
- String errorInfo = String.format("发票: %s, 购买方税号为空", fileName);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 购买方税号为空, 文件名={}", fileName);
- }
- // ========== 校验2:发票号重复校验 ==========
- if (StringUtils.isNotBlank(invoiceNumber)) {
- // 检查数据库中是否已存在相同的发票号
- InvoiceLibrary existingInvoice = baseMapper.selectByInvoiceNumber(invoiceNumber);
- if (existingInvoice != null) {
- String errorMsg = String.format("发票号重复: %s (当前文件: %s, 已存在于OA审批单: %s)",
- invoiceNumber, fileName, existingInvoice.getOaId());
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- // 同时检查同一审批单内是否有重复
- if (invoiceNumberList.contains(invoiceNumber)) {
- String errorMsg = String.format("当前审批单内发票号重复: %s (当前文件: %s, 已存在文件: %s)",
- invoiceNumber, fileName, invoiceNumberToFileName.get(invoiceNumber));
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- invoiceNumberList.add(invoiceNumber);
- invoiceNumberToFileName.put(invoiceNumber, fileName);
- }
- }
- }
- } catch (Exception e) {
- log.error("发票解析异常: fileId={}, fileName={}", fileId, fileName, e);
- terminateWorkflow(accessToken, processInstanceId, userId, "发票解析失败: " + e.getMessage());
- return McR.error("400", "发票解析失败: " + e.getMessage());
- }
- }
- } else if ("共享".equals(hasInvoice)) {
- // 收集共享发票数据,待第二遍遍历时保存
- if (detailje != null && StringUtils.isNotBlank(detailje)) {
- Map<String, Object> sharedData = new HashMap<>();
- sharedData.put("detailje", detailje);
- sharedData.put("cdbm", cdbm);
- sharedData.put("hasInvoice", hasInvoice);
- sharedInvoiceDataList.add(sharedData);
- log.info("收集共享发票数据: 金额={}, 成本部门={}", detailje, cdbm);
- }
- }
- }
- // ========== 抬头校验失败处理 ==========
- if (!invalidBuyerTaxIds.isEmpty()) {
- String errorMsg = "发票抬头有误,以下发票的购买方税号不在公司抬头库中:\n" + String.join("\n", invalidBuyerTaxIds);
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- BigDecimal totalAmount = BigDecimal.ZERO;
- // ========== 第二遍遍历:保存发票数据(校验通过后) ==========
- // 1. 保存普通发票数据
- for (Map<String, Object> parsedData : parsedInvoiceDataList) {
- JSONObject invoice = (JSONObject) parsedData.get("invoice");
- Object responseData = parsedData.get("responseData");
- String cdbm = (String) parsedData.get("cdbm");
- String hasInvoice = (String) parsedData.get("hasInvoice");
- String detailje = (String) parsedData.get("detailje"); // 修改为 String 类型
- allResults.add(responseData);
- // 汇总 amount
- BigDecimal amount = invoice.getBigDecimal("amount");
- if (amount != null) {
- totalAmount = totalAmount.add(amount);
- }
- // 构建InvoiceLibrary对象
- InvoiceLibrary invoiceLibrary = new InvoiceLibrary();
- invoiceLibrary.setOaId(processInstanceId);
- invoiceLibrary.setInvoiceCode(invoice.getString("code") != null ? invoice.getString("code") : "");
- invoiceLibrary.setInvoiceNumber(invoice.getString("serial") != null ? invoice.getString("serial") : "");
- invoiceLibrary.setInvoiceType(invoice.getString("kindName") != null ? invoice.getString("kindName") : "");
- String date = invoice.getString("date");
- if (StringUtils.isNotBlank(date)) {
- try {
- invoiceLibrary.setInvoiceDate(LocalDate.parse(date.trim()));
- } catch (Exception e) {
- log.warn("日期解析失败: {}", date);
- }
- }
- invoiceLibrary.setAmount(invoice.getBigDecimal("excludingTax") != null ? invoice.getBigDecimal("excludingTax") : BigDecimal.ZERO);
- invoiceLibrary.setTaxAmount(invoice.getBigDecimal("tax") != null ? invoice.getBigDecimal("tax") : BigDecimal.ZERO);
- invoiceLibrary.setTotalAmount(invoice.getBigDecimal("amount") != null ? invoice.getBigDecimal("amount") : BigDecimal.ZERO);
- invoiceLibrary.setBuyerName(invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "");
- invoiceLibrary.setBuyerTaxId(invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "");
- invoiceLibrary.setSellerName(invoice.getString("sellerName") != null ? invoice.getString("sellerName") : "");
- invoiceLibrary.setSellerTaxId(invoice.getString("sellerTaxId") != null ? invoice.getString("sellerTaxId") : "");
- invoiceLibrary.setOaStatus("0");
- invoiceLibrary.setFormName("付款申请");
- invoiceLibrary.setPaySubject(fkzhxx != null ? fkzhxx : "");
- invoiceLibrary.setPayAccount(fkzh != null ? fkzh : "");
- invoiceLibrary.setBankName(yhqc != null ? yhqc : "");
- invoiceLibrary.setIsLongTerm(sfct != null ? sfct : "");
- invoiceLibrary.setInvoiceStatus("0");
- invoiceLibrary.setHasInvoice(hasInvoice);
- // 处理 detailAmount,将 String 转换为 BigDecimal
- if (detailje != null && StringUtils.isNotBlank(detailje)) {
- try {
- invoiceLibrary.setDetailAmount(new BigDecimal(detailje));
- } catch (NumberFormatException e) {
- log.error("detailJe格式转换失败: {}", detailje);
- invoiceLibrary.setDetailAmount(null);
- }
- } else {
- invoiceLibrary.setDetailAmount(null);
- }
- // 普通发票不涉及共享字段,设置为 null
- invoiceLibrary.setSharedTaxAmount(null);
- invoiceLibrary.setSharedAmount(null);
- invoiceLibrary.setSharedRate(null);
- invoiceLibrary.setAccountTitle(bxlb != null ? bxlb : "");
- invoiceLibrary.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- invoiceLibrary.setCreatedAt(LocalDateTime.now());
- invoiceLibrary.setUpdatedAt(LocalDateTime.now());
- // 设置成本部门
- if (cdbm != null && StringUtils.isNotBlank(cdbm)) {
- invoiceLibrary.setDep(cdbm);
- } else {
- invoiceLibrary.setDep(bm != null ? bm : "");
- }
- invoiceList.add(invoiceLibrary);
- }
- for (Map<String, Object> sharedData : sharedInvoiceDataList) {
- String detailje = (String) sharedData.get("detailje");
- String cdbm = (String) sharedData.get("cdbm");
- String hasInvoice = (String) sharedData.get("hasInvoice");
- try {
- BigDecimal detailAmount = new BigDecimal(detailje);
- // 使用从普通发票中解析到的税率
- BigDecimal ocrTaxRate = sharedTaxRate;
- if (ocrTaxRate.compareTo(BigDecimal.ZERO) == 0) {
- log.warn("共享发票税率未获取到,使用默认税率0,金额={}", detailAmount);
- }
- // 计算金额: 含税金额 / (1 + 税率) = 税额
- BigDecimal divisor = BigDecimal.ONE.add(ocrTaxRate);
- BigDecimal sharedTaxAmount = detailAmount.divide(divisor, 2, BigDecimal.ROUND_HALF_UP);
- BigDecimal sharedAmount = detailAmount.subtract(sharedTaxAmount);
- BigDecimal sharedRate = ocrTaxRate; // 这是小数形式的税率,如 0.09
- log.info("共享发票计算: 含税金额={}, 税率={}%, 不含税金额={}, 税额={}",
- detailAmount, ocrTaxRate.multiply(new BigDecimal("100")),
- sharedAmount, sharedTaxAmount);
- // 保存共享发票数据
- InvoiceLibrary sharedInvoice = new InvoiceLibrary();
- sharedInvoice.setOaId(processInstanceId);
- sharedInvoice.setOaStatus("0");
- sharedInvoice.setInvoiceStatus("0");
- sharedInvoice.setDep(cdbm != null && StringUtils.isNotBlank(cdbm) ? cdbm : (bm != null ? bm : ""));
- sharedInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- sharedInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- sharedInvoice.setAmount(null);
- sharedInvoice.setTaxAmount(null);
- sharedInvoice.setTotalAmount(null); // 共享发票不设置总金额
- sharedInvoice.setFormName("付款申请");
- sharedInvoice.setPaySubject(fkzhxx != null ? fkzhxx : "");
- sharedInvoice.setPayAccount(fkzh != null ? fkzh : "");
- sharedInvoice.setBankName(yhqc != null ? yhqc : "");
- sharedInvoice.setIsLongTerm(sfct != null ? sfct : "");
- sharedInvoice.setHasInvoice(hasInvoice);
- sharedInvoice.setDetailAmount(detailAmount);
- // 共享发票字段设置值 - 修正:存储数字而不是带百分号的字符串
- sharedInvoice.setSharedTaxAmount(sharedAmount);
- sharedInvoice.setSharedAmount(sharedTaxAmount);
- sharedInvoice.setSharedRate(String.valueOf(sharedRate)); // 直接存储小数,如 0.09
- sharedInvoice.setCreatedAt(LocalDateTime.now());
- sharedInvoice.setUpdatedAt(LocalDateTime.now());
- sharedInvoice.setInvoiceCode("");
- sharedInvoice.setInvoiceNumber("");
- sharedInvoice.setInvoiceType(sharedKind);
- sharedInvoice.setBuyerName("");
- sharedInvoice.setBuyerTaxId("");
- sharedInvoice.setSellerName("");
- sharedInvoice.setSellerTaxId("");
- invoiceList.add(sharedInvoice);
- log.info("成功保存共享发票记录,成本部门: {}", cdbm);
- } catch (NumberFormatException e) {
- log.error("共享发票金额格式转换失败: detailje={}", detailje, e);
- } catch (Exception e) {
- log.error("共享发票处理失败", e);
- }
- }
- // 保存发票记录
- if (!invoiceList.isEmpty()) {
- for (InvoiceLibrary invoice : invoiceList) {
- baseMapper.insert(invoice);
- }
- log.info("成功保存 {} 条发票记录(普通发票: {}, 共享发票: {})",
- invoiceList.size(), parsedInvoiceDataList.size(), sharedInvoiceDataList.size());
- }
- addWorkflowComment1(processInstanceId, userId, totalAmount);
- return McR.success(allResults);
- } catch (Exception e) {
- log.error("解析子表数据失败", e);
- return McR.error("300", "解析数据失败: " + e.getMessage());
- }
- }
- }
- }
- return McR.success();
- } catch (Exception e) {
- log.error("处理审批实例失败", e);
- return McR.error("500", "系统处理失败: " + e.getMessage());
- }
- }
- @Override
- public McR invoiceLibrary2(Map map) {
- log.info("接收到的参数: {}", map);
- try {
- String processInstanceId = UtilMap.getString(map, "processInstanceId");
- if (StringUtils.isBlank(processInstanceId)) {
- log.error("processInstanceId为空");
- return McR.error("400", "审批实例ID不能为空");
- }
- // 获取审批实例信息
- String accessToken = ddClient.getAccessToken();
- Map processInstance = ddClientWorkflow.getProcessInstanceId(accessToken, processInstanceId);
- if (processInstance == null) {
- log.error("获取审批实例失败: {}", processInstanceId);
- return McR.error("500", "获取审批实例信息失败");
- }
- String userId = (String) processInstance.get("originatorUserId");
- log.info("审批人ID: {}", userId);
- List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
- if (formComponentValues == null || formComponentValues.isEmpty()) {
- log.warn("表单数据为空");
- return McR.error("400", "表单数据为空");
- }
- // 存储主表的字段值
- String zt = null;
- BigDecimal mainJe = null;
- String bxlb = null;
- String bm = null;
- String fkzhxx = null;
- String fkzh = null;
- String yhqc = null;
- String sfct = null;
- // 遍历收集主表字段值
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- Object value = formComponentValue.get("value");
- if ("DDSelectField_15ZO6PMU1ZC00".equals(id)) {
- zt = value != null ? String.valueOf(value) : "";
- }
- if ("MoneyField_1V4A9P72K6TC0".equals(id)) {
- if (value instanceof BigDecimal) {
- mainJe = (BigDecimal) value;
- } else if (value != null) {
- try {
- mainJe = new BigDecimal(String.valueOf(value));
- } catch (NumberFormatException e) {
- log.error("金额格式转换失败: {}", value);
- mainJe = BigDecimal.ZERO;
- }
- }
- }
- if ("DDSelectField_YLLB7AD1ATS0".equals(id)) {
- bxlb = value != null ? String.valueOf(value) : "";
- }
- if ("DepartmentField_ZI9KALEYOTC0".equals(id)) {
- bm = value != null ? String.valueOf(value) : "";
- }
- if ("DDSelectField_1WEX2WWCJ3PC0".equals(id)) {
- fkzhxx = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_2W39FPCZH1A0".equals(id)) {
- fkzh = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_QW7HJIR7T800".equals(id)) {
- yhqc = value != null ? String.valueOf(value) : "";
- }
- if ("DDSelectField_12JNC3P1K5V40".equals(id)) {
- sfct = value != null ? String.valueOf(value) : "否";
- }
- }
- // 判断主表状态 - 无发票
- if ("否".equals(zt)) {
- // 保存基础报销记录
- InvoiceLibrary baseInvoice = new InvoiceLibrary();
- baseInvoice.setOaId(processInstanceId);
- baseInvoice.setOaStatus("0");
- baseInvoice.setInvoiceStatus("0");
- baseInvoice.setDep(bm != null ? bm : "");
- baseInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- baseInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- baseInvoice.setCreatedAt(LocalDateTime.now());
- baseInvoice.setUpdatedAt(LocalDateTime.now());
- baseInvoice.setInvoiceCode("");
- baseInvoice.setInvoiceNumber("");
- baseInvoice.setInvoiceType("");
- baseInvoice.setAmount(BigDecimal.ZERO);
- baseInvoice.setTaxAmount(BigDecimal.ZERO);
- baseInvoice.setTotalAmount(BigDecimal.ZERO);
- baseInvoice.setBuyerName("");
- baseInvoice.setBuyerTaxId("");
- baseInvoice.setSellerName("");
- baseInvoice.setSellerTaxId("");
- baseInvoice.setFormName("合作商付款申请");
- baseInvoice.setPaySubject(fkzhxx != null ? fkzhxx : "");
- baseInvoice.setPayAccount(fkzh != null ? fkzh : "");
- baseInvoice.setBankName(yhqc != null ? yhqc : "");
- baseInvoice.setIsLongTerm(sfct != null ? sfct : "");
- baseInvoice.setHasInvoice("否");
- baseInvoice.setDetailAmount(null);
- baseInvoice.setSharedTaxAmount(null);
- baseInvoice.setSharedAmount(null);
- baseInvoice.setSharedRate(null);
- baseMapper.insert(baseInvoice);
- addWorkflowComment(processInstanceId, userId, "报销总金额:" + mainJe);
- return McR.success();
- }
- // 判断主表状态 - 有发票
- if ("是".equals(zt)) {
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- if ("TableField_182UNZEX02U80".equals(id)) {
- String tableFieldValue = String.valueOf(formComponentValue.get("value"));
- log.info("子表数据: {}", tableFieldValue);
- try {
- List<Map> tableRows = (List<Map>) JSONObject.parse(tableFieldValue);
- if (tableRows == null || tableRows.isEmpty()) {
- log.warn("子表数据为空");
- return McR.error("400", "发票明细为空");
- }
- List<Object> allResults = new ArrayList<>();
- List<InvoiceLibrary> invoiceList = new ArrayList<>();
- // 存储第一遍解析的发票数据,避免重复解析
- List<Map<String, Object>> parsedInvoiceDataList = new ArrayList<>();
- // 存储共享发票数据
- List<Map<String, Object>> sharedInvoiceDataList = new ArrayList<>();
- // 用于校验的集合
- List<String> invoiceNumberList = new ArrayList<>();
- Map<String, String> invoiceNumberToFileName = new HashMap<>();
- List<String> invalidBuyerTaxIds = new ArrayList<>();
- // 存储税率值,供共享发票使用
- BigDecimal sharedTaxRate = BigDecimal.ZERO;
- String sharedKind = "";
- // ========== 第一遍遍历:收集并校验所有发票数据 ==========
- for (Map row : tableRows) {
- List<Map> rowValues = (List<Map>) row.get("rowValue");
- String hasInvoice = null;
- String cdbm = null;
- String detailje = null;
- List<Map> attachmentList = null;
- for (Map rowItem : rowValues) {
- String key = String.valueOf(rowItem.get("key"));
- if ("DDSelectField_44I0SP6M1I00".equals(key)) {
- Object value = rowItem.get("value");
- hasInvoice = value != null ? String.valueOf(value) : "";
- }
- if ("DepartmentField_RC2YZRJQAQ80".equals(key)) {
- Object value = rowItem.get("value");
- cdbm = value != null ? String.valueOf(value) : "";
- }
- if ("NumberField_1UC3HZ8OEIPS0".equals(key)) {
- Object value = rowItem.get("value");
- detailje = value != null ? String.valueOf(value) : "";
- }
- if ("DDAttachment_LEUWYIC68TC0".equals(key)) {
- Object value = rowItem.get("value");
- if (value instanceof List) {
- attachmentList = (List<Map>) value;
- }
- }
- }
- if ("是".equals(hasInvoice) && attachmentList != null && !attachmentList.isEmpty()) {
- for (Map attachment : attachmentList) {
- String fileId = UtilMap.getString(attachment, "fileId");
- String fileType = UtilMap.getString(attachment, "fileType");
- String fileName = UtilMap.getString(attachment, "fileName");
- try {
- String filePath = downloadPath + fileId + "." + fileType;
- downloadDdFile(processInstanceId, fileId, filePath);
- String hz = "qw/files/" + fileId + "." + fileType;
- Map fileMap = new HashMap();
- fileMap.put("url", url + hz);
- fileMap.put("size", new File(filePath).length() / 1024f / 1024f);
- fileMap.put("isPdf", "pdf".equalsIgnoreCase(fileType));
- McR<Object> result = processMixedInvoice(fileMap);
- Object responseData = result.getData();
- // 解析发票数据
- if (responseData != null) {
- String jsonStr = JSONObject.toJSONString(responseData);
- JSONObject jsonObject = JSONObject.parseObject(jsonStr);
- JSONArray resultArray = jsonObject.getJSONArray("result");
- if (resultArray != null && !resultArray.isEmpty()) {
- JSONObject invoice = resultArray.getJSONObject(0);
- String invoiceNumber = invoice.getString("serial") != null ? invoice.getString("serial") : "";
- String buyerTaxId = invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "";
- String buyerName = invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "";
- // 获取税率,供共享发票使用
- Object taxRateObj = invoice.get("taxRate");
- Object kind = invoice.getString("kindName");
- if (taxRateObj != null) {
- String taxRateStr = String.valueOf(taxRateObj);
- String taxRateNum = taxRateStr.replace("%", "").trim();
- sharedKind = kind != null ? String.valueOf(kind) : "";
- sharedTaxRate = new BigDecimal(taxRateNum);
- sharedTaxRate = sharedTaxRate.divide(new BigDecimal("100"), 10, BigDecimal.ROUND_HALF_UP);
- log.info("从有发票中获取税率: 原始={}, 转换后={}", taxRateStr, sharedTaxRate);
- }
- // 保存解析的数据供后续使用
- Map<String, Object> parsedData = new HashMap<>();
- parsedData.put("invoice", invoice);
- parsedData.put("fileId", fileId);
- parsedData.put("fileName", fileName);
- parsedData.put("fileType", fileType);
- parsedData.put("cdbm", cdbm);
- parsedData.put("hasInvoice", hasInvoice);
- parsedData.put("detailje", detailje);
- parsedData.put("responseData", responseData);
- parsedInvoiceDataList.add(parsedData);
- // ========== 校验1:抬头校验 ==========
- if (StringUtils.isNotBlank(buyerName)) {
- CompanyTitle existingTitle = companyTitleMapper.selectByTaxId(buyerName);
- if (existingTitle == null) {
- String errorInfo = String.format("发票: %s, 购买方名称: %s, 税号: %s",
- fileName, buyerName, buyerTaxId);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 税号={} 不存在于抬头库, 文件名={}", buyerTaxId, fileName);
- }
- } else {
- String errorInfo = String.format("发票: %s, 购买方税号为空", fileName);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 购买方税号为空, 文件名={}", fileName);
- }
- // ========== 校验2:发票号重复校验 ==========
- if (StringUtils.isNotBlank(invoiceNumber)) {
- // 检查数据库中是否已存在相同的发票号
- InvoiceLibrary existingInvoice = baseMapper.selectByInvoiceNumber(invoiceNumber);
- if (existingInvoice != null) {
- String errorMsg = String.format("发票号重复: %s (当前文件: %s, 已存在于OA审批单: %s)",
- invoiceNumber, fileName, existingInvoice.getOaId());
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- // 同时检查同一审批单内是否有重复
- if (invoiceNumberList.contains(invoiceNumber)) {
- String errorMsg = String.format("当前审批单内发票号重复: %s (当前文件: %s, 已存在文件: %s)",
- invoiceNumber, fileName, invoiceNumberToFileName.get(invoiceNumber));
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- invoiceNumberList.add(invoiceNumber);
- invoiceNumberToFileName.put(invoiceNumber, fileName);
- }
- }
- }
- } catch (Exception e) {
- log.error("发票解析异常: fileId={}, fileName={}", fileId, fileName, e);
- terminateWorkflow(accessToken, processInstanceId, userId, "发票解析失败: " + e.getMessage());
- return McR.error("400", "发票解析失败: " + e.getMessage());
- }
- }
- } else if ("共享".equals(hasInvoice)) {
- // 收集共享发票数据,待第二遍遍历时保存
- if (detailje != null && StringUtils.isNotBlank(detailje)) {
- Map<String, Object> sharedData = new HashMap<>();
- sharedData.put("detailje", detailje);
- sharedData.put("cdbm", cdbm);
- sharedData.put("hasInvoice", hasInvoice);
- sharedInvoiceDataList.add(sharedData);
- log.info("收集共享发票数据: 金额={}, 成本部门={}", detailje, cdbm);
- }
- }
- }
- // ========== 抬头校验失败处理 ==========
- if (!invalidBuyerTaxIds.isEmpty()) {
- String errorMsg = "发票抬头有误,以下发票的购买方税号不在公司抬头库中:\n" + String.join("\n", invalidBuyerTaxIds);
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- BigDecimal totalAmount = BigDecimal.ZERO;
- // ========== 第二遍遍历:保存发票数据(校验通过后) ==========
- // 1. 保存普通发票数据
- for (Map<String, Object> parsedData : parsedInvoiceDataList) {
- JSONObject invoice = (JSONObject) parsedData.get("invoice");
- Object responseData = parsedData.get("responseData");
- String cdbm = (String) parsedData.get("cdbm");
- String hasInvoice = (String) parsedData.get("hasInvoice");
- String detailje = (String) parsedData.get("detailje"); // 修改为 String 类型
- allResults.add(responseData);
- // 汇总 amount
- BigDecimal amount = invoice.getBigDecimal("amount");
- if (amount != null) {
- totalAmount = totalAmount.add(amount);
- }
- // 构建InvoiceLibrary对象
- InvoiceLibrary invoiceLibrary = new InvoiceLibrary();
- invoiceLibrary.setOaId(processInstanceId);
- invoiceLibrary.setInvoiceCode(invoice.getString("code") != null ? invoice.getString("code") : "");
- invoiceLibrary.setInvoiceNumber(invoice.getString("serial") != null ? invoice.getString("serial") : "");
- invoiceLibrary.setInvoiceType(invoice.getString("kindName") != null ? invoice.getString("kindName") : "");
- String date = invoice.getString("date");
- if (StringUtils.isNotBlank(date)) {
- try {
- invoiceLibrary.setInvoiceDate(LocalDate.parse(date.trim()));
- } catch (Exception e) {
- log.warn("日期解析失败: {}", date);
- }
- }
- invoiceLibrary.setAmount(invoice.getBigDecimal("excludingTax") != null ? invoice.getBigDecimal("excludingTax") : BigDecimal.ZERO);
- invoiceLibrary.setTaxAmount(invoice.getBigDecimal("tax") != null ? invoice.getBigDecimal("tax") : BigDecimal.ZERO);
- invoiceLibrary.setTotalAmount(invoice.getBigDecimal("amount") != null ? invoice.getBigDecimal("amount") : BigDecimal.ZERO);
- invoiceLibrary.setBuyerName(invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "");
- invoiceLibrary.setBuyerTaxId(invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "");
- invoiceLibrary.setSellerName(invoice.getString("sellerName") != null ? invoice.getString("sellerName") : "");
- invoiceLibrary.setSellerTaxId(invoice.getString("sellerTaxId") != null ? invoice.getString("sellerTaxId") : "");
- invoiceLibrary.setOaStatus("0");
- invoiceLibrary.setFormName("合作商付款申请");
- invoiceLibrary.setPaySubject(fkzhxx != null ? fkzhxx : "");
- invoiceLibrary.setPayAccount(fkzh != null ? fkzh : "");
- invoiceLibrary.setBankName(yhqc != null ? yhqc : "");
- invoiceLibrary.setIsLongTerm(sfct != null ? sfct : "");
- invoiceLibrary.setInvoiceStatus("0");
- invoiceLibrary.setHasInvoice(hasInvoice);
- // 处理 detailAmount,将 String 转换为 BigDecimal
- if (detailje != null && StringUtils.isNotBlank(detailje)) {
- try {
- invoiceLibrary.setDetailAmount(new BigDecimal(detailje));
- } catch (NumberFormatException e) {
- log.error("detailJe格式转换失败: {}", detailje);
- invoiceLibrary.setDetailAmount(null);
- }
- } else {
- invoiceLibrary.setDetailAmount(null);
- }
- // 普通发票不涉及共享字段,设置为 null
- invoiceLibrary.setSharedTaxAmount(null);
- invoiceLibrary.setSharedAmount(null);
- invoiceLibrary.setSharedRate(null);
- invoiceLibrary.setAccountTitle(bxlb != null ? bxlb : "");
- invoiceLibrary.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- invoiceLibrary.setCreatedAt(LocalDateTime.now());
- invoiceLibrary.setUpdatedAt(LocalDateTime.now());
- // 设置成本部门
- if (cdbm != null && StringUtils.isNotBlank(cdbm)) {
- invoiceLibrary.setDep(cdbm);
- } else {
- invoiceLibrary.setDep(bm != null ? bm : "");
- }
- invoiceList.add(invoiceLibrary);
- }
- for (Map<String, Object> sharedData : sharedInvoiceDataList) {
- String detailje = (String) sharedData.get("detailje");
- String cdbm = (String) sharedData.get("cdbm");
- String hasInvoice = (String) sharedData.get("hasInvoice");
- try {
- BigDecimal detailAmount = new BigDecimal(detailje);
- // 使用从普通发票中解析到的税率
- BigDecimal ocrTaxRate = sharedTaxRate;
- if (ocrTaxRate.compareTo(BigDecimal.ZERO) == 0) {
- log.warn("共享发票税率未获取到,使用默认税率0,金额={}", detailAmount);
- }
- // 计算金额: 含税金额 / (1 + 税率) = 税额
- BigDecimal divisor = BigDecimal.ONE.add(ocrTaxRate);
- BigDecimal sharedTaxAmount = detailAmount.divide(divisor, 2, BigDecimal.ROUND_HALF_UP);
- BigDecimal sharedAmount = detailAmount.subtract(sharedTaxAmount);
- BigDecimal sharedRate = ocrTaxRate; // 这是小数形式的税率,如 0.09
- log.info("共享发票计算: 含税金额={}, 税率={}%, 不含税金额={}, 税额={}",
- detailAmount, ocrTaxRate.multiply(new BigDecimal("100")),
- sharedAmount, sharedTaxAmount);
- // 保存共享发票数据
- InvoiceLibrary sharedInvoice = new InvoiceLibrary();
- sharedInvoice.setOaId(processInstanceId);
- sharedInvoice.setOaStatus("0");
- sharedInvoice.setInvoiceStatus("0");
- sharedInvoice.setDep(cdbm != null && StringUtils.isNotBlank(cdbm) ? cdbm : (bm != null ? bm : ""));
- sharedInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- sharedInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- sharedInvoice.setAmount(null);
- sharedInvoice.setTaxAmount(null);
- sharedInvoice.setTotalAmount(null); // 共享发票不设置总金额
- sharedInvoice.setFormName("合作商付款申请");
- sharedInvoice.setPaySubject(fkzhxx != null ? fkzhxx : "");
- sharedInvoice.setPayAccount(fkzh != null ? fkzh : "");
- sharedInvoice.setBankName(yhqc != null ? yhqc : "");
- sharedInvoice.setIsLongTerm(sfct != null ? sfct : "");
- sharedInvoice.setHasInvoice(hasInvoice);
- sharedInvoice.setDetailAmount(detailAmount);
- // 共享发票字段设置值 - 修正:存储数字而不是带百分号的字符串
- sharedInvoice.setSharedTaxAmount(sharedAmount);
- sharedInvoice.setSharedAmount(sharedTaxAmount);
- sharedInvoice.setSharedRate(String.valueOf(sharedRate)); // 直接存储小数,如 0.09
- sharedInvoice.setCreatedAt(LocalDateTime.now());
- sharedInvoice.setUpdatedAt(LocalDateTime.now());
- sharedInvoice.setInvoiceCode("");
- sharedInvoice.setInvoiceNumber("");
- sharedInvoice.setInvoiceType(sharedKind);
- sharedInvoice.setBuyerName("");
- sharedInvoice.setBuyerTaxId("");
- sharedInvoice.setSellerName("");
- sharedInvoice.setSellerTaxId("");
- invoiceList.add(sharedInvoice);
- log.info("成功保存共享发票记录,成本部门: {}", cdbm);
- } catch (NumberFormatException e) {
- log.error("共享发票金额格式转换失败: detailje={}", detailje, e);
- } catch (Exception e) {
- log.error("共享发票处理失败", e);
- }
- }
- // 保存发票记录
- if (!invoiceList.isEmpty()) {
- for (InvoiceLibrary invoice : invoiceList) {
- baseMapper.insert(invoice);
- }
- log.info("成功保存 {} 条发票记录(普通发票: {}, 共享发票: {})",
- invoiceList.size(), parsedInvoiceDataList.size(), sharedInvoiceDataList.size());
- }
- addWorkflowComment1(processInstanceId, userId, totalAmount);
- return McR.success(allResults);
- } catch (Exception e) {
- log.error("解析子表数据失败", e);
- return McR.error("300", "解析数据失败: " + e.getMessage());
- }
- }
- }
- }
- return McR.success();
- } catch (Exception e) {
- log.error("处理审批实例失败", e);
- return McR.error("500", "系统处理失败: " + e.getMessage());
- }
- }
- @Override
- public McR invoiceLibrary3(Map map) {
- log.info("接收到的参数: {}", map);
- try {
- String processInstanceId = UtilMap.getString(map, "processInstanceId");
- if (StringUtils.isBlank(processInstanceId)) {
- log.error("processInstanceId为空");
- return McR.error("400", "审批实例ID不能为空");
- }
- // 获取审批实例信息
- String accessToken = ddClient.getAccessToken();
- Map processInstance = ddClientWorkflow.getProcessInstanceId(accessToken, processInstanceId);
- if (processInstance == null) {
- log.error("获取审批实例失败: {}", processInstanceId);
- return McR.error("500", "获取审批实例信息失败");
- }
- String userId = (String) processInstance.get("originatorUserId");
- log.info("审批人ID: {}", userId);
- List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
- if (formComponentValues == null || formComponentValues.isEmpty()) {
- log.warn("表单数据为空");
- return McR.error("400", "表单数据为空");
- }
- // 存储主表的字段值
- String zt = null;
- BigDecimal mainJe = null;
- String bxlb = null;
- String bm = null;
- String fkzhxx = null;
- String fkzh = null;
- String yhqc = null;
- String sfct = null;
- // 遍历收集主表字段值
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- Object value = formComponentValue.get("value");
- if ("DDSelectField_19B5ZAI2SE000".equals(id)) {
- zt = value != null ? String.valueOf(value) : "";//ocr识别
- }
- if ("MoneyField_5U5SLLA3CS40".equals(id)) {
- if (value instanceof BigDecimal) {
- mainJe = (BigDecimal) value;
- } else if (value != null) {
- try {
- mainJe = new BigDecimal(String.valueOf(value));
- } catch (NumberFormatException e) {
- log.error("金额格式转换失败: {}", value);
- mainJe = BigDecimal.ZERO;
- }
- }
- }
- if ("DDSelectField_BS1HCMO7YTK0".equals(id)) {
- bxlb = value != null ? String.valueOf(value) : "";
- }
- // if ("DepartmentField_ZI9KALEYOTC0".equals(id)) {
- // bm = value != null ? String.valueOf(value) : "";
- // }
- if ("DDSelectField_GLW8YHBHSLS0".equals(id)) {
- fkzhxx = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_1PR1HQ4H28SG0".equals(id)) {
- fkzh = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_1UPR1XZTI3VK".equals(id)) {
- yhqc = value != null ? String.valueOf(value) : "";
- }
- if ("DDSelectField_1TMBRS8T7DPC0".equals(id)) {
- sfct = value != null ? String.valueOf(value) : "否";
- }
- }
- // 判断主表状态 - 无发票
- if ("否".equals(zt)) {
- // 保存基础报销记录
- InvoiceLibrary baseInvoice = new InvoiceLibrary();
- baseInvoice.setOaId(processInstanceId);
- baseInvoice.setOaStatus("0");
- baseInvoice.setInvoiceStatus("0");
- baseInvoice.setDep(bm != null ? bm : "");
- baseInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- baseInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- baseInvoice.setCreatedAt(LocalDateTime.now());
- baseInvoice.setUpdatedAt(LocalDateTime.now());
- baseInvoice.setInvoiceCode("");
- baseInvoice.setInvoiceNumber("");
- baseInvoice.setInvoiceType("");
- baseInvoice.setAmount(BigDecimal.ZERO);
- baseInvoice.setTaxAmount(BigDecimal.ZERO);
- baseInvoice.setTotalAmount(BigDecimal.ZERO);
- baseInvoice.setBuyerName("");
- baseInvoice.setBuyerTaxId("");
- baseInvoice.setSellerName("");
- baseInvoice.setSellerTaxId("");
- baseInvoice.setFormName("合作商报销申请");
- baseInvoice.setPaySubject(fkzhxx != null ? fkzhxx : "");
- baseInvoice.setPayAccount(fkzh != null ? fkzh : "");
- baseInvoice.setBankName(yhqc != null ? yhqc : "");
- baseInvoice.setIsLongTerm(sfct != null ? sfct : "");
- baseInvoice.setHasInvoice("否");
- baseInvoice.setDetailAmount(null);
- baseInvoice.setSharedTaxAmount(null);
- baseInvoice.setSharedAmount(null);
- baseInvoice.setSharedRate(null);
- baseMapper.insert(baseInvoice);
- addWorkflowComment(processInstanceId, userId, "报销总金额:" + mainJe);
- return McR.success();
- }
- // 判断主表状态 - 有发票
- if ("是".equals(zt)) {
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- if ("TableField_9LJ65U3CQ980".equals(id)) {
- String tableFieldValue = String.valueOf(formComponentValue.get("value"));
- log.info("子表数据: {}", tableFieldValue);
- try {
- List<Map> tableRows = (List<Map>) JSONObject.parse(tableFieldValue);
- if (tableRows == null || tableRows.isEmpty()) {
- log.warn("子表数据为空");
- return McR.error("400", "发票明细为空");
- }
- List<Object> allResults = new ArrayList<>();
- List<InvoiceLibrary> invoiceList = new ArrayList<>();
- // 存储第一遍解析的发票数据,避免重复解析
- List<Map<String, Object>> parsedInvoiceDataList = new ArrayList<>();
- // 存储共享发票数据
- List<Map<String, Object>> sharedInvoiceDataList = new ArrayList<>();
- // 用于校验的集合
- List<String> invoiceNumberList = new ArrayList<>();
- Map<String, String> invoiceNumberToFileName = new HashMap<>();
- List<String> invalidBuyerTaxIds = new ArrayList<>();
- // 存储税率值,供共享发票使用
- BigDecimal sharedTaxRate = BigDecimal.ZERO;
- String sharedKind = "";
- // ========== 第一遍遍历:收集并校验所有发票数据 ==========
- for (Map row : tableRows) {
- List<Map> rowValues = (List<Map>) row.get("rowValue");
- String hasInvoice = null;
- String cdbm = null;
- String detailje = null;
- List<Map> attachmentList = null;
- for (Map rowItem : rowValues) {
- String key = String.valueOf(rowItem.get("key"));
- if ("DDSelectField_TTTOAI0FDXJ4".equals(key)) {
- Object value = rowItem.get("value");
- hasInvoice = value != null ? String.valueOf(value) : "";
- }
- if ("DepartmentField_15QGD1PV69XC0".equals(key)) {
- Object value = rowItem.get("value");
- cdbm = value != null ? String.valueOf(value) : "";
- }
- if ("NumberField_FYHZK218TTDS".equals(key)) {
- Object value = rowItem.get("value");
- detailje = value != null ? String.valueOf(value) : "";
- }
- if ("DDAttachment_XVU9V89QOEM8".equals(key)) {
- Object value = rowItem.get("value");
- if (value instanceof List) {
- attachmentList = (List<Map>) value;
- }
- }
- }
- if ("是".equals(hasInvoice) && attachmentList != null && !attachmentList.isEmpty()) {
- for (Map attachment : attachmentList) {
- String fileId = UtilMap.getString(attachment, "fileId");
- String fileType = UtilMap.getString(attachment, "fileType");
- String fileName = UtilMap.getString(attachment, "fileName");
- try {
- String filePath = downloadPath + fileId + "." + fileType;
- downloadDdFile(processInstanceId, fileId, filePath);
- String hz = "qw/files/" + fileId + "." + fileType;
- Map fileMap = new HashMap();
- fileMap.put("url", url + hz);
- fileMap.put("size", new File(filePath).length() / 1024f / 1024f);
- fileMap.put("isPdf", "pdf".equalsIgnoreCase(fileType));
- McR<Object> result = processMixedInvoice(fileMap);
- Object responseData = result.getData();
- // 解析发票数据
- if (responseData != null) {
- String jsonStr = JSONObject.toJSONString(responseData);
- JSONObject jsonObject = JSONObject.parseObject(jsonStr);
- JSONArray resultArray = jsonObject.getJSONArray("result");
- if (resultArray != null && !resultArray.isEmpty()) {
- JSONObject invoice = resultArray.getJSONObject(0);
- String invoiceNumber = invoice.getString("serial") != null ? invoice.getString("serial") : "";
- String buyerTaxId = invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "";
- String buyerName = invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "";
- // 获取税率,供共享发票使用
- Object taxRateObj = invoice.get("taxRate");
- Object kind = invoice.getString("kindName");
- if (taxRateObj != null) {
- String taxRateStr = String.valueOf(taxRateObj);
- String taxRateNum = taxRateStr.replace("%", "").trim();
- sharedKind = kind != null ? String.valueOf(kind) : "";
- sharedTaxRate = new BigDecimal(taxRateNum);
- sharedTaxRate = sharedTaxRate.divide(new BigDecimal("100"), 10, BigDecimal.ROUND_HALF_UP);
- log.info("从有发票中获取税率: 原始={}, 转换后={}", taxRateStr, sharedTaxRate);
- }
- // 保存解析的数据供后续使用
- Map<String, Object> parsedData = new HashMap<>();
- parsedData.put("invoice", invoice);
- parsedData.put("fileId", fileId);
- parsedData.put("fileName", fileName);
- parsedData.put("fileType", fileType);
- parsedData.put("cdbm", cdbm);
- parsedData.put("hasInvoice", hasInvoice);
- parsedData.put("detailje", detailje);
- parsedData.put("responseData", responseData);
- parsedInvoiceDataList.add(parsedData);
- // ========== 校验1:抬头校验 ==========
- if (StringUtils.isNotBlank(buyerName)) {
- CompanyTitle existingTitle = companyTitleMapper.selectByTaxId(buyerName);
- if (existingTitle == null) {
- String errorInfo = String.format("发票: %s, 购买方名称: %s, 税号: %s",
- fileName, buyerName, buyerTaxId);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 税号={} 不存在于抬头库, 文件名={}", buyerTaxId, fileName);
- }
- } else {
- String errorInfo = String.format("发票: %s, 购买方税号为空", fileName);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 购买方税号为空, 文件名={}", fileName);
- }
- // ========== 校验2:发票号重复校验 ==========
- if (StringUtils.isNotBlank(invoiceNumber)) {
- // 检查数据库中是否已存在相同的发票号
- InvoiceLibrary existingInvoice = baseMapper.selectByInvoiceNumber(invoiceNumber);
- if (existingInvoice != null) {
- String errorMsg = String.format("发票号重复: %s (当前文件: %s, 已存在于OA审批单: %s)",
- invoiceNumber, fileName, existingInvoice.getOaId());
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- // 同时检查同一审批单内是否有重复
- if (invoiceNumberList.contains(invoiceNumber)) {
- String errorMsg = String.format("当前审批单内发票号重复: %s (当前文件: %s, 已存在文件: %s)",
- invoiceNumber, fileName, invoiceNumberToFileName.get(invoiceNumber));
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- invoiceNumberList.add(invoiceNumber);
- invoiceNumberToFileName.put(invoiceNumber, fileName);
- }
- }
- }
- } catch (Exception e) {
- log.error("发票解析异常: fileId={}, fileName={}", fileId, fileName, e);
- terminateWorkflow(accessToken, processInstanceId, userId, "发票解析失败: " + e.getMessage());
- return McR.error("400", "发票解析失败: " + e.getMessage());
- }
- }
- } else if ("共享".equals(hasInvoice)) {
- // 收集共享发票数据,待第二遍遍历时保存
- if (detailje != null && StringUtils.isNotBlank(detailje)) {
- Map<String, Object> sharedData = new HashMap<>();
- sharedData.put("detailje", detailje);
- sharedData.put("cdbm", cdbm);
- sharedData.put("hasInvoice", hasInvoice);
- sharedInvoiceDataList.add(sharedData);
- log.info("收集共享发票数据: 金额={}, 成本部门={}", detailje, cdbm);
- }
- }
- }
- // ========== 抬头校验失败处理 ==========
- if (!invalidBuyerTaxIds.isEmpty()) {
- String errorMsg = "发票抬头有误,以下发票的购买方税号不在公司抬头库中:\n" + String.join("\n", invalidBuyerTaxIds);
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- BigDecimal totalAmount = BigDecimal.ZERO;
- // ========== 第二遍遍历:保存发票数据(校验通过后) ==========
- // 1. 保存普通发票数据
- for (Map<String, Object> parsedData : parsedInvoiceDataList) {
- JSONObject invoice = (JSONObject) parsedData.get("invoice");
- Object responseData = parsedData.get("responseData");
- String cdbm = (String) parsedData.get("cdbm");
- String hasInvoice = (String) parsedData.get("hasInvoice");
- String detailje = (String) parsedData.get("detailje"); // 修改为 String 类型
- allResults.add(responseData);
- // 汇总 amount
- BigDecimal amount = invoice.getBigDecimal("amount");
- if (amount != null) {
- totalAmount = totalAmount.add(amount);
- }
- // 构建InvoiceLibrary对象
- InvoiceLibrary invoiceLibrary = new InvoiceLibrary();
- invoiceLibrary.setOaId(processInstanceId);
- invoiceLibrary.setInvoiceCode(invoice.getString("code") != null ? invoice.getString("code") : "");
- invoiceLibrary.setInvoiceNumber(invoice.getString("serial") != null ? invoice.getString("serial") : "");
- invoiceLibrary.setInvoiceType(invoice.getString("kindName") != null ? invoice.getString("kindName") : "");
- String date = invoice.getString("date");
- if (StringUtils.isNotBlank(date)) {
- try {
- invoiceLibrary.setInvoiceDate(LocalDate.parse(date.trim()));
- } catch (Exception e) {
- log.warn("日期解析失败: {}", date);
- }
- }
- invoiceLibrary.setAmount(invoice.getBigDecimal("excludingTax") != null ? invoice.getBigDecimal("excludingTax") : BigDecimal.ZERO);
- invoiceLibrary.setTaxAmount(invoice.getBigDecimal("tax") != null ? invoice.getBigDecimal("tax") : BigDecimal.ZERO);
- invoiceLibrary.setTotalAmount(invoice.getBigDecimal("amount") != null ? invoice.getBigDecimal("amount") : BigDecimal.ZERO);
- invoiceLibrary.setBuyerName(invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "");
- invoiceLibrary.setBuyerTaxId(invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "");
- invoiceLibrary.setSellerName(invoice.getString("sellerName") != null ? invoice.getString("sellerName") : "");
- invoiceLibrary.setSellerTaxId(invoice.getString("sellerTaxId") != null ? invoice.getString("sellerTaxId") : "");
- invoiceLibrary.setOaStatus("0");
- invoiceLibrary.setFormName("合作商报销申请");
- invoiceLibrary.setPaySubject(fkzhxx != null ? fkzhxx : "");
- invoiceLibrary.setPayAccount(fkzh != null ? fkzh : "");
- invoiceLibrary.setBankName(yhqc != null ? yhqc : "");
- invoiceLibrary.setIsLongTerm(sfct != null ? sfct : "");
- invoiceLibrary.setInvoiceStatus("0");
- invoiceLibrary.setHasInvoice(hasInvoice);
- // 处理 detailAmount,将 String 转换为 BigDecimal
- if (detailje != null && StringUtils.isNotBlank(detailje)) {
- try {
- invoiceLibrary.setDetailAmount(new BigDecimal(detailje));
- } catch (NumberFormatException e) {
- log.error("detailJe格式转换失败: {}", detailje);
- invoiceLibrary.setDetailAmount(null);
- }
- } else {
- invoiceLibrary.setDetailAmount(null);
- }
- // 普通发票不涉及共享字段,设置为 null
- invoiceLibrary.setSharedTaxAmount(null);
- invoiceLibrary.setSharedAmount(null);
- invoiceLibrary.setSharedRate(null);
- invoiceLibrary.setAccountTitle(bxlb != null ? bxlb : "");
- invoiceLibrary.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- invoiceLibrary.setCreatedAt(LocalDateTime.now());
- invoiceLibrary.setUpdatedAt(LocalDateTime.now());
- // 设置成本部门
- if (cdbm != null && StringUtils.isNotBlank(cdbm)) {
- invoiceLibrary.setDep(cdbm);
- } else {
- invoiceLibrary.setDep(bm != null ? bm : "");
- }
- invoiceList.add(invoiceLibrary);
- }
- for (Map<String, Object> sharedData : sharedInvoiceDataList) {
- String detailje = (String) sharedData.get("detailje");
- String cdbm = (String) sharedData.get("cdbm");
- String hasInvoice = (String) sharedData.get("hasInvoice");
- try {
- BigDecimal detailAmount = new BigDecimal(detailje);
- // 使用从普通发票中解析到的税率
- BigDecimal ocrTaxRate = sharedTaxRate;
- if (ocrTaxRate.compareTo(BigDecimal.ZERO) == 0) {
- log.warn("共享发票税率未获取到,使用默认税率0,金额={}", detailAmount);
- }
- // 计算金额: 含税金额 / (1 + 税率) = 税额
- BigDecimal divisor = BigDecimal.ONE.add(ocrTaxRate);
- BigDecimal sharedTaxAmount = detailAmount.divide(divisor, 2, BigDecimal.ROUND_HALF_UP);
- BigDecimal sharedAmount = detailAmount.subtract(sharedTaxAmount);
- BigDecimal sharedRate = ocrTaxRate; // 这是小数形式的税率,如 0.09
- log.info("共享发票计算: 含税金额={}, 税率={}%, 不含税金额={}, 税额={}",
- detailAmount, ocrTaxRate.multiply(new BigDecimal("100")),
- sharedAmount, sharedTaxAmount);
- // 保存共享发票数据
- InvoiceLibrary sharedInvoice = new InvoiceLibrary();
- sharedInvoice.setOaId(processInstanceId);
- sharedInvoice.setOaStatus("0");
- sharedInvoice.setInvoiceStatus("0");
- sharedInvoice.setDep(cdbm != null && StringUtils.isNotBlank(cdbm) ? cdbm : (bm != null ? bm : ""));
- sharedInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- sharedInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- sharedInvoice.setAmount(null);
- sharedInvoice.setTaxAmount(null);
- sharedInvoice.setTotalAmount(null); // 共享发票不设置总金额
- sharedInvoice.setFormName("合作商报销申请");
- sharedInvoice.setPaySubject(fkzhxx != null ? fkzhxx : "");
- sharedInvoice.setPayAccount(fkzh != null ? fkzh : "");
- sharedInvoice.setBankName(yhqc != null ? yhqc : "");
- sharedInvoice.setIsLongTerm(sfct != null ? sfct : "");
- sharedInvoice.setHasInvoice(hasInvoice);
- sharedInvoice.setDetailAmount(detailAmount);
- // 共享发票字段设置值 - 修正:存储数字而不是带百分号的字符串
- sharedInvoice.setSharedTaxAmount(sharedAmount);
- sharedInvoice.setSharedAmount(sharedTaxAmount);
- sharedInvoice.setSharedRate(String.valueOf(sharedRate)); // 直接存储小数,如 0.09
- sharedInvoice.setCreatedAt(LocalDateTime.now());
- sharedInvoice.setUpdatedAt(LocalDateTime.now());
- sharedInvoice.setInvoiceCode("");
- sharedInvoice.setInvoiceNumber("");
- sharedInvoice.setInvoiceType(sharedKind);
- sharedInvoice.setBuyerName("");
- sharedInvoice.setBuyerTaxId("");
- sharedInvoice.setSellerName("");
- sharedInvoice.setSellerTaxId("");
- invoiceList.add(sharedInvoice);
- log.info("成功保存共享发票记录,成本部门: {}", cdbm);
- } catch (NumberFormatException e) {
- log.error("共享发票金额格式转换失败: detailje={}", detailje, e);
- } catch (Exception e) {
- log.error("共享发票处理失败", e);
- }
- }
- // 保存发票记录
- if (!invoiceList.isEmpty()) {
- for (InvoiceLibrary invoice : invoiceList) {
- baseMapper.insert(invoice);
- }
- log.info("成功保存 {} 条发票记录(普通发票: {}, 共享发票: {})",
- invoiceList.size(), parsedInvoiceDataList.size(), sharedInvoiceDataList.size());
- }
- addWorkflowComment1(processInstanceId, userId, totalAmount);
- return McR.success(allResults);
- } catch (Exception e) {
- log.error("解析子表数据失败", e);
- return McR.error("300", "解析数据失败: " + e.getMessage());
- }
- }
- }
- }
- return McR.success();
- } catch (Exception e) {
- log.error("处理审批实例失败", e);
- return McR.error("500", "系统处理失败: " + e.getMessage());
- }
- }
- @Override
- public McR invoiceLibrary5(Map map) {
- log.info("接收到的参数: {}", map);
- try {
- String processInstanceId = UtilMap.getString(map, "processInstanceId");
- if (StringUtils.isBlank(processInstanceId)) {
- log.error("processInstanceId为空");
- return McR.error("400", "审批实例ID不能为空");
- }
- // 获取审批实例信息
- String accessToken = ddClient.getAccessToken();
- Map processInstance = ddClientWorkflow.getProcessInstanceId(accessToken, processInstanceId);
- if (processInstance == null) {
- log.error("获取审批实例失败: {}", processInstanceId);
- return McR.error("500", "获取审批实例信息失败");
- }
- String userId = (String) processInstance.get("originatorUserId");
- log.info("审批人ID: {}", userId);
- List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
- if (formComponentValues == null || formComponentValues.isEmpty()) {
- log.warn("表单数据为空");
- return McR.error("400", "表单数据为空");
- }
- // 存储主表的字段值
- String zt = null;
- BigDecimal mainJe = null;
- String bxlb = null;
- String bm = null;
- String fkzhxx = null;
- String fkzh = null;
- String yhqc = null;
- String sfct = null;
- // 遍历收集主表字段值
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- Object value = formComponentValue.get("value");
- if ("DDSelectField_7F1V8IJJ9QG".equals(id)) {
- zt = value != null ? String.valueOf(value) : "";//ocr识别
- }
- if ("MoneyField_1435GRXGYPA80".equals(id)) {
- if (value instanceof BigDecimal) {
- mainJe = (BigDecimal) value;
- } else if (value != null) {
- try {
- mainJe = new BigDecimal(String.valueOf(value));
- } catch (NumberFormatException e) {
- log.error("金额格式转换失败: {}", value);
- mainJe = BigDecimal.ZERO;
- }
- }
- }
- if ("DDSelectField_1UX0JVU89Q000".equals(id)) {
- bxlb = value != null ? String.valueOf(value) : "";
- }
- if ("DepartmentField_1BJT6UY9Y5B40".equals(id)) {
- bm = value != null ? String.valueOf(value) : "";
- }
- if ("DDSelectField_1D77TV92WXEO0".equals(id)) {
- fkzhxx = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_3CQPLF9BVBO0".equals(id)) {
- fkzh = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_YSFYQQ305SG0".equals(id)) {
- yhqc = value != null ? String.valueOf(value) : "";
- }
- if ("DDSelectField_1AYKIPZ3435S0".equals(id)) {
- sfct = value != null ? String.valueOf(value) : "否";
- }
- }
- // 判断主表状态 - 无发票
- if ("否".equals(zt)) {
- // 保存基础报销记录
- InvoiceLibrary baseInvoice = new InvoiceLibrary();
- baseInvoice.setOaId(processInstanceId);
- baseInvoice.setOaStatus("0");
- baseInvoice.setInvoiceStatus("0");
- baseInvoice.setDep(bm != null ? bm : "");
- baseInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- baseInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- baseInvoice.setCreatedAt(LocalDateTime.now());
- baseInvoice.setUpdatedAt(LocalDateTime.now());
- baseInvoice.setInvoiceCode("");
- baseInvoice.setInvoiceNumber("");
- baseInvoice.setInvoiceType("");
- baseInvoice.setAmount(BigDecimal.ZERO);
- baseInvoice.setTaxAmount(BigDecimal.ZERO);
- baseInvoice.setTotalAmount(BigDecimal.ZERO);
- baseInvoice.setBuyerName("");
- baseInvoice.setBuyerTaxId("");
- baseInvoice.setSellerName("");
- baseInvoice.setSellerTaxId("");
- baseInvoice.setFormName("出差费用报销");
- baseInvoice.setPaySubject(fkzhxx != null ? fkzhxx : "");
- baseInvoice.setPayAccount(fkzh != null ? fkzh : "");
- baseInvoice.setBankName(yhqc != null ? yhqc : "");
- baseInvoice.setIsLongTerm(sfct != null ? sfct : "");
- baseInvoice.setHasInvoice("否");
- baseInvoice.setDetailAmount(null);
- baseInvoice.setSharedTaxAmount(null);
- baseInvoice.setSharedAmount(null);
- baseInvoice.setSharedRate(null);
- baseMapper.insert(baseInvoice);
- addWorkflowComment(processInstanceId, userId, "报销总金额:" + mainJe);
- return McR.success();
- }
- // 判断主表状态 - 有发票
- if ("是".equals(zt)) {
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- if ("TableField_169TONKJ3KW00".equals(id)) {
- String tableFieldValue = String.valueOf(formComponentValue.get("value"));
- log.info("子表数据: {}", tableFieldValue);
- try {
- List<Map> tableRows = (List<Map>) JSONObject.parse(tableFieldValue);
- if (tableRows == null || tableRows.isEmpty()) {
- log.warn("子表数据为空");
- return McR.error("400", "发票明细为空");
- }
- List<Object> allResults = new ArrayList<>();
- List<InvoiceLibrary> invoiceList = new ArrayList<>();
- // 存储第一遍解析的发票数据,避免重复解析
- List<Map<String, Object>> parsedInvoiceDataList = new ArrayList<>();
- // 存储共享发票数据
- List<Map<String, Object>> sharedInvoiceDataList = new ArrayList<>();
- // 用于校验的集合
- List<String> invoiceNumberList = new ArrayList<>();
- Map<String, String> invoiceNumberToFileName = new HashMap<>();
- List<String> invalidBuyerTaxIds = new ArrayList<>();
- // 存储税率值,供共享发票使用
- BigDecimal sharedTaxRate = BigDecimal.ZERO;
- String sharedKind = "";
- // ========== 第一遍遍历:收集并校验所有发票数据 ==========
- for (Map row : tableRows) {
- List<Map> rowValues = (List<Map>) row.get("rowValue");
- String hasInvoice = null;
- String cdbm = null;
- String detailje = null;
- List<Map> attachmentList = null;
- for (Map rowItem : rowValues) {
- String key = String.valueOf(rowItem.get("key"));
- if ("DDSelectField_1G6XMYA3FMCG0".equals(key)) {
- Object value = rowItem.get("value");
- hasInvoice = value != null ? String.valueOf(value) : "";
- }
- if ("DepartmentField_KJIWTTZLE800".equals(key)) {
- Object value = rowItem.get("value");
- cdbm = value != null ? String.valueOf(value) : "";
- }
- if ("NumberField_L0ALER5S6180".equals(key)) {
- Object value = rowItem.get("value");
- detailje = value != null ? String.valueOf(value) : "";
- }
- if ("DDAttachment_EPL7ILUTD0G0".equals(key)) {
- Object value = rowItem.get("value");
- if (value instanceof List) {
- attachmentList = (List<Map>) value;
- }
- }
- }
- if ("是".equals(hasInvoice) && attachmentList != null && !attachmentList.isEmpty()) {
- for (Map attachment : attachmentList) {
- String fileId = UtilMap.getString(attachment, "fileId");
- String fileType = UtilMap.getString(attachment, "fileType");
- String fileName = UtilMap.getString(attachment, "fileName");
- try {
- String filePath = downloadPath + fileId + "." + fileType;
- downloadDdFile(processInstanceId, fileId, filePath);
- String hz = "qw/files/" + fileId + "." + fileType;
- Map fileMap = new HashMap();
- fileMap.put("url", url + hz);
- fileMap.put("size", new File(filePath).length() / 1024f / 1024f);
- fileMap.put("isPdf", "pdf".equalsIgnoreCase(fileType));
- McR<Object> result = processMixedInvoice(fileMap);
- Object responseData = result.getData();
- // 解析发票数据
- if (responseData != null) {
- String jsonStr = JSONObject.toJSONString(responseData);
- JSONObject jsonObject = JSONObject.parseObject(jsonStr);
- JSONArray resultArray = jsonObject.getJSONArray("result");
- if (resultArray != null && !resultArray.isEmpty()) {
- JSONObject invoice = resultArray.getJSONObject(0);
- String invoiceNumber = invoice.getString("serial") != null ? invoice.getString("serial") : "";
- String buyerTaxId = invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "";
- String buyerName = invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "";
- // 获取税率,供共享发票使用
- Object taxRateObj = invoice.get("taxRate");
- Object kind = invoice.getString("kindName");
- if (taxRateObj != null) {
- String taxRateStr = String.valueOf(taxRateObj);
- String taxRateNum = taxRateStr.replace("%", "").trim();
- sharedKind = kind != null ? String.valueOf(kind) : "";
- sharedTaxRate = new BigDecimal(taxRateNum);
- sharedTaxRate = sharedTaxRate.divide(new BigDecimal("100"), 10, BigDecimal.ROUND_HALF_UP);
- log.info("从有发票中获取税率: 原始={}, 转换后={}", taxRateStr, sharedTaxRate);
- }
- // 保存解析的数据供后续使用
- Map<String, Object> parsedData = new HashMap<>();
- parsedData.put("invoice", invoice);
- parsedData.put("fileId", fileId);
- parsedData.put("fileName", fileName);
- parsedData.put("fileType", fileType);
- parsedData.put("cdbm", cdbm);
- parsedData.put("hasInvoice", hasInvoice);
- parsedData.put("detailje", detailje);
- parsedData.put("responseData", responseData);
- parsedInvoiceDataList.add(parsedData);
- // ========== 校验1:抬头校验 ==========
- if (StringUtils.isNotBlank(buyerName)) {
- CompanyTitle existingTitle = companyTitleMapper.selectByTaxId(buyerName);
- if (existingTitle == null) {
- String errorInfo = String.format("发票: %s, 购买方名称: %s, 税号: %s",
- fileName, buyerName, buyerTaxId);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 税号={} 不存在于抬头库, 文件名={}", buyerTaxId, fileName);
- }
- } else {
- String errorInfo = String.format("发票: %s, 购买方税号为空", fileName);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 购买方税号为空, 文件名={}", fileName);
- }
- // ========== 校验2:发票号重复校验 ==========
- if (StringUtils.isNotBlank(invoiceNumber)) {
- // 检查数据库中是否已存在相同的发票号
- InvoiceLibrary existingInvoice = baseMapper.selectByInvoiceNumber(invoiceNumber);
- if (existingInvoice != null) {
- String errorMsg = String.format("发票号重复: %s (当前文件: %s, 已存在于OA审批单: %s)",
- invoiceNumber, fileName, existingInvoice.getOaId());
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- // 同时检查同一审批单内是否有重复
- if (invoiceNumberList.contains(invoiceNumber)) {
- String errorMsg = String.format("当前审批单内发票号重复: %s (当前文件: %s, 已存在文件: %s)",
- invoiceNumber, fileName, invoiceNumberToFileName.get(invoiceNumber));
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- invoiceNumberList.add(invoiceNumber);
- invoiceNumberToFileName.put(invoiceNumber, fileName);
- }
- }
- }
- } catch (Exception e) {
- log.error("发票解析异常: fileId={}, fileName={}", fileId, fileName, e);
- terminateWorkflow(accessToken, processInstanceId, userId, "发票解析失败: " + e.getMessage());
- return McR.error("400", "发票解析失败: " + e.getMessage());
- }
- }
- } else if ("共享".equals(hasInvoice)) {
- // 收集共享发票数据,待第二遍遍历时保存
- if (detailje != null && StringUtils.isNotBlank(detailje)) {
- Map<String, Object> sharedData = new HashMap<>();
- sharedData.put("detailje", detailje);
- sharedData.put("cdbm", cdbm);
- sharedData.put("hasInvoice", hasInvoice);
- sharedInvoiceDataList.add(sharedData);
- log.info("收集共享发票数据: 金额={}, 成本部门={}", detailje, cdbm);
- }
- }
- }
- // ========== 抬头校验失败处理 ==========
- if (!invalidBuyerTaxIds.isEmpty()) {
- String errorMsg = "发票抬头有误,以下发票的购买方税号不在公司抬头库中:\n" + String.join("\n", invalidBuyerTaxIds);
- log.error(errorMsg);
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- BigDecimal totalAmount = BigDecimal.ZERO;
- // ========== 第二遍遍历:保存发票数据(校验通过后) ==========
- // 1. 保存普通发票数据
- for (Map<String, Object> parsedData : parsedInvoiceDataList) {
- JSONObject invoice = (JSONObject) parsedData.get("invoice");
- Object responseData = parsedData.get("responseData");
- String cdbm = (String) parsedData.get("cdbm");
- String hasInvoice = (String) parsedData.get("hasInvoice");
- String detailje = (String) parsedData.get("detailje"); // 修改为 String 类型
- allResults.add(responseData);
- // 汇总 amount
- BigDecimal amount = invoice.getBigDecimal("amount");
- if (amount != null) {
- totalAmount = totalAmount.add(amount);
- }
- // 构建InvoiceLibrary对象
- InvoiceLibrary invoiceLibrary = new InvoiceLibrary();
- invoiceLibrary.setOaId(processInstanceId);
- invoiceLibrary.setInvoiceCode(invoice.getString("code") != null ? invoice.getString("code") : "");
- invoiceLibrary.setInvoiceNumber(invoice.getString("serial") != null ? invoice.getString("serial") : "");
- invoiceLibrary.setInvoiceType(invoice.getString("kindName") != null ? invoice.getString("kindName") : "");
- String date = invoice.getString("date");
- if (StringUtils.isNotBlank(date)) {
- try {
- invoiceLibrary.setInvoiceDate(LocalDate.parse(date.trim()));
- } catch (Exception e) {
- log.warn("日期解析失败: {}", date);
- }
- }
- invoiceLibrary.setAmount(invoice.getBigDecimal("excludingTax") != null ? invoice.getBigDecimal("excludingTax") : BigDecimal.ZERO);
- invoiceLibrary.setTaxAmount(invoice.getBigDecimal("tax") != null ? invoice.getBigDecimal("tax") : BigDecimal.ZERO);
- invoiceLibrary.setTotalAmount(invoice.getBigDecimal("amount") != null ? invoice.getBigDecimal("amount") : BigDecimal.ZERO);
- invoiceLibrary.setBuyerName(invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "");
- invoiceLibrary.setBuyerTaxId(invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "");
- invoiceLibrary.setSellerName(invoice.getString("sellerName") != null ? invoice.getString("sellerName") : "");
- invoiceLibrary.setSellerTaxId(invoice.getString("sellerTaxId") != null ? invoice.getString("sellerTaxId") : "");
- invoiceLibrary.setOaStatus("0");
- invoiceLibrary.setFormName("出差费用报销");
- invoiceLibrary.setPaySubject(fkzhxx != null ? fkzhxx : "");
- invoiceLibrary.setPayAccount(fkzh != null ? fkzh : "");
- invoiceLibrary.setBankName(yhqc != null ? yhqc : "");
- invoiceLibrary.setIsLongTerm(sfct != null ? sfct : "");
- invoiceLibrary.setInvoiceStatus("0");
- invoiceLibrary.setHasInvoice(hasInvoice);
- // 处理 detailAmount,将 String 转换为 BigDecimal
- if (detailje != null && StringUtils.isNotBlank(detailje)) {
- try {
- invoiceLibrary.setDetailAmount(new BigDecimal(detailje));
- } catch (NumberFormatException e) {
- log.error("detailJe格式转换失败: {}", detailje);
- invoiceLibrary.setDetailAmount(null);
- }
- } else {
- invoiceLibrary.setDetailAmount(null);
- }
- // 普通发票不涉及共享字段,设置为 null
- invoiceLibrary.setSharedTaxAmount(null);
- invoiceLibrary.setSharedAmount(null);
- invoiceLibrary.setSharedRate(null);
- invoiceLibrary.setAccountTitle(bxlb != null ? bxlb : "");
- invoiceLibrary.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- invoiceLibrary.setCreatedAt(LocalDateTime.now());
- invoiceLibrary.setUpdatedAt(LocalDateTime.now());
- // 设置成本部门
- if (cdbm != null && StringUtils.isNotBlank(cdbm)) {
- invoiceLibrary.setDep(cdbm);
- } else {
- invoiceLibrary.setDep(bm != null ? bm : "");
- }
- invoiceList.add(invoiceLibrary);
- }
- for (Map<String, Object> sharedData : sharedInvoiceDataList) {
- String detailje = (String) sharedData.get("detailje");
- String cdbm = (String) sharedData.get("cdbm");
- String hasInvoice = (String) sharedData.get("hasInvoice");
- try {
- BigDecimal detailAmount = new BigDecimal(detailje);
- // 使用从普通发票中解析到的税率
- BigDecimal ocrTaxRate = sharedTaxRate;
- if (ocrTaxRate.compareTo(BigDecimal.ZERO) == 0) {
- log.warn("共享发票税率未获取到,使用默认税率0,金额={}", detailAmount);
- }
- // 计算金额: 含税金额 / (1 + 税率) = 税额
- BigDecimal divisor = BigDecimal.ONE.add(ocrTaxRate);
- BigDecimal sharedTaxAmount = detailAmount.divide(divisor, 2, BigDecimal.ROUND_HALF_UP);
- BigDecimal sharedAmount = detailAmount.subtract(sharedTaxAmount);
- BigDecimal sharedRate = ocrTaxRate; // 这是小数形式的税率,如 0.09
- log.info("共享发票计算: 含税金额={}, 税率={}%, 不含税金额={}, 税额={}",
- detailAmount, ocrTaxRate.multiply(new BigDecimal("100")),
- sharedAmount, sharedTaxAmount);
- // 保存共享发票数据
- InvoiceLibrary sharedInvoice = new InvoiceLibrary();
- sharedInvoice.setOaId(processInstanceId);
- sharedInvoice.setOaStatus("0");
- sharedInvoice.setInvoiceStatus("0");
- sharedInvoice.setDep(cdbm != null && StringUtils.isNotBlank(cdbm) ? cdbm : (bm != null ? bm : ""));
- sharedInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- sharedInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- sharedInvoice.setAmount(null);
- sharedInvoice.setTaxAmount(null);
- sharedInvoice.setTotalAmount(null); // 共享发票不设置总金额
- sharedInvoice.setFormName("出差费用报销");
- sharedInvoice.setPaySubject(fkzhxx != null ? fkzhxx : "");
- sharedInvoice.setPayAccount(fkzh != null ? fkzh : "");
- sharedInvoice.setBankName(yhqc != null ? yhqc : "");
- sharedInvoice.setIsLongTerm(sfct != null ? sfct : "");
- sharedInvoice.setHasInvoice(hasInvoice);
- sharedInvoice.setDetailAmount(detailAmount);
- // 共享发票字段设置值 - 修正:存储数字而不是带百分号的字符串
- sharedInvoice.setSharedTaxAmount(sharedAmount);
- sharedInvoice.setSharedAmount(sharedTaxAmount);
- sharedInvoice.setSharedRate(String.valueOf(sharedRate)); // 直接存储小数,如 0.09
- sharedInvoice.setCreatedAt(LocalDateTime.now());
- sharedInvoice.setUpdatedAt(LocalDateTime.now());
- sharedInvoice.setInvoiceCode("");
- sharedInvoice.setInvoiceNumber("");
- sharedInvoice.setInvoiceType(sharedKind);
- sharedInvoice.setBuyerName("");
- sharedInvoice.setBuyerTaxId("");
- sharedInvoice.setSellerName("");
- sharedInvoice.setSellerTaxId("");
- invoiceList.add(sharedInvoice);
- log.info("成功保存共享发票记录,成本部门: {}", cdbm);
- } catch (NumberFormatException e) {
- log.error("共享发票金额格式转换失败: detailje={}", detailje, e);
- } catch (Exception e) {
- log.error("共享发票处理失败", e);
- }
- }
- // 保存发票记录
- if (!invoiceList.isEmpty()) {
- for (InvoiceLibrary invoice : invoiceList) {
- baseMapper.insert(invoice);
- }
- log.info("成功保存 {} 条发票记录(普通发票: {}, 共享发票: {})",
- invoiceList.size(), parsedInvoiceDataList.size(), sharedInvoiceDataList.size());
- }
- addWorkflowComment1(processInstanceId, userId, totalAmount);
- return McR.success(allResults);
- } catch (Exception e) {
- log.error("解析子表数据失败", e);
- return McR.error("300", "解析数据失败: " + e.getMessage());
- }
- }
- }
- }
- return McR.success();
- } catch (Exception e) {
- log.error("处理审批实例失败", e);
- return McR.error("500", "系统处理失败: " + e.getMessage());
- }
- }
- @Override
- public McR invoiceLibrary6(Map map) {
- log.info("接收到的参数: {}", map);
- try {
- String processInstanceId = UtilMap.getString(map, "processInstanceId");
- if (StringUtils.isBlank(processInstanceId)) {
- log.error("processInstanceId为空");
- return McR.error("400", "审批实例ID不能为空");
- }
- // 获取审批实例信息
- String accessToken = ddClient.getAccessToken();
- Map processInstance = ddClientWorkflow.getProcessInstanceId(accessToken, processInstanceId);
- if (processInstance == null) {
- log.error("获取审批实例失败: {}", processInstanceId);
- return McR.error("500", "获取审批实例信息失败");
- }
- String userId = (String) processInstance.get("originatorUserId");
- log.info("审批人ID: {}", userId);
- List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
- if (formComponentValues == null || formComponentValues.isEmpty()) {
- log.warn("表单数据为空");
- return McR.error("400", "表单数据为空");
- }
- // 存储主表的字段值
- String zt = null;
- BigDecimal mainJe = null;
- String bxlb = null;
- String bm = null;
- String fkzhxx = null;
- String fkzh = null;
- String yhqc = null;
- String sfct = null;
- // 遍历收集主表字段值
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- Object value = formComponentValue.get("value");
- if ("DDSelectField_VWIFJ1JZK0W0".equals(id)) {
- zt = value != null ? String.valueOf(value) : "";
- }
- if ("MoneyField_3QS10ALLABU0".equals(id)) {
- if (value instanceof BigDecimal) {
- mainJe = (BigDecimal) value;
- } else if (value != null) {
- try {
- mainJe = new BigDecimal(String.valueOf(value));
- } catch (NumberFormatException e) {
- log.error("金额格式转换失败: {}", value, e);
- mainJe = BigDecimal.ZERO;
- }
- }
- }
- // 如果需要这两个字段,请取消注释并填写正确的字段ID
- if ("DDSelectField_YLLB7AD1ATS0".equals(id)) {
- bxlb = value != null ? String.valueOf(value) : "";
- }
- if ("DepartmentField_RF93A6VHA9C0".equals(id)) {
- bm = value != null ? String.valueOf(value) : "";
- }
- if ("DDSelectField_IQXAGL7Z8XC0".equals(id)) {
- fkzhxx = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_3W9CLQOZZ540".equals(id)) {
- fkzh = value != null ? String.valueOf(value) : "";
- }
- if ("TextField_9PJ4JW8KTCS0".equals(id)) {
- yhqc = value != null ? String.valueOf(value) : "";
- }
- if ("DDSelectField_21L6KT7DT70G0".equals(id)) {
- sfct = value != null ? String.valueOf(value) : "否";
- }
- }
- // 判断主表状态 - 无发票
- if ("否".equals(zt)) {
- // Map<String, Object> result = new HashMap<>();
- // result.put("je", mainJe);
- // result.put("status", "否");
- // result.put("message", "无发票报销");
- // 保存基础报销记录
- InvoiceLibrary baseInvoice = new InvoiceLibrary();
- baseInvoice.setOaId(processInstanceId);
- baseInvoice.setOaStatus("0");
- baseInvoice.setInvoiceStatus("0");
- baseInvoice.setDep(bm != null ? bm : "");
- baseInvoice.setAccountTitle(bxlb != null ? bxlb : "");
- baseInvoice.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- baseInvoice.setCreatedAt(LocalDateTime.now());
- baseInvoice.setUpdatedAt(LocalDateTime.now());
- baseInvoice.setInvoiceCode("");
- baseInvoice.setInvoiceNumber("");
- baseInvoice.setInvoiceType("");
- baseInvoice.setAmount(BigDecimal.ZERO);
- baseInvoice.setTaxAmount(BigDecimal.ZERO);
- baseInvoice.setTotalAmount(BigDecimal.ZERO);
- baseInvoice.setBuyerName("");
- baseInvoice.setFormName("批量付款申请(一对多)");
- baseInvoice.setPaySubject(fkzhxx != null ? fkzhxx : "");
- baseInvoice.setPayAccount(fkzh != null ? fkzh : "");
- baseInvoice.setBankName(yhqc != null ? yhqc : "");
- baseInvoice.setIsLongTerm(sfct != null ? sfct : "");
- baseInvoice.setBuyerTaxId("");
- baseInvoice.setSellerName("");
- baseInvoice.setSellerTaxId("");
- baseMapper.insert(baseInvoice);
- addWorkflowComment(processInstanceId, userId, "报销总金额:"+mainJe);
- return McR.success();
- }
- // 判断主表状态 - 有发票
- if ("是".equals(zt)) {
- for (Map formComponentValue : formComponentValues) {
- String id = String.valueOf(formComponentValue.get("id"));
- if ("DDAttachment_1C1GRYIRFJOG0".equals(id)) {
- // 获取附件value(它是一个JSON字符串)
- Object attachmentValue = formComponentValue.get("value");
- List<Map> attachmentList = null;
- // 解析附件JSON字符串
- if (attachmentValue != null) {
- String attachmentJsonStr = String.valueOf(attachmentValue);
- if (StringUtils.isNotBlank(attachmentJsonStr)) {
- try {
- attachmentList = JSONObject.parseArray(attachmentJsonStr, Map.class);
- log.info("解析附件列表成功,共{}个附件", attachmentList != null ? attachmentList.size() : 0);
- } catch (Exception e) {
- log.error("解析附件JSON失败: {}", attachmentJsonStr, e);
- return McR.error("400", "附件格式解析失败");
- }
- }
- }
- try {
- List<Object> allResults = new ArrayList<>();
- List<InvoiceLibrary> invoiceList = new ArrayList<>();
- // 用于校验的集合
- List<String> invoiceNumberList = new ArrayList<>();
- Map<String, String> invoiceNumberToFileName = new HashMap<>();
- List<String> invalidBuyerTaxIds = new ArrayList<>();
- // 存储第一遍解析的发票数据,避免重复解析
- List<Map<String, Object>> parsedInvoiceDataList = new ArrayList<>();
- if (attachmentList != null && !attachmentList.isEmpty()) {
- for (Map attachment : attachmentList) {
- String fileId = UtilMap.getString(attachment, "fileId");
- String fileType = UtilMap.getString(attachment, "fileType");
- String fileName = UtilMap.getString(attachment, "fileName");
- // 参数校验
- if (StringUtils.isBlank(fileId) || StringUtils.isBlank(fileType)) {
- log.warn("文件信息不完整: fileId={}, fileType={}, fileName={}", fileId, fileType, fileName);
- continue;
- }
- try {
- String filePath = downloadPath + fileId + "." + fileType;
- downloadDdFile(processInstanceId, fileId, filePath);
- String hz = "qw/files/" + fileId + "." + fileType;
- Map fileMap = new HashMap();
- fileMap.put("url", url + hz);
- fileMap.put("size", new File(filePath).length() / 1024f / 1024f);
- fileMap.put("isPdf", "pdf".equalsIgnoreCase(fileType));
- McR<Object> result = processMixedInvoice(fileMap);
- Object responseData = result.getData();
- // 解析发票数据
- if (responseData != null) {
- String jsonStr = JSONObject.toJSONString(responseData);
- JSONObject jsonObject = JSONObject.parseObject(jsonStr);
- JSONArray resultArray = jsonObject.getJSONArray("result");
- if (resultArray != null && !resultArray.isEmpty()) {
- JSONObject invoice = resultArray.getJSONObject(0);
- String invoiceNumber = invoice.getString("serial") != null ? invoice.getString("serial") : "";
- String buyerTaxId = invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "";
- String buyerName = invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "";
- // 保存解析的数据供后续使用
- Map<String, Object> parsedData = new HashMap<>();
- parsedData.put("invoice", invoice);
- parsedData.put("fileId", fileId);
- parsedData.put("fileName", fileName);
- parsedData.put("fileType", fileType);
- parsedData.put("responseData", responseData);
- parsedInvoiceDataList.add(parsedData);
- // ========== 校验1:抬头校验 ==========
- if (StringUtils.isNotBlank(buyerName)) {
- CompanyTitle existingTitle = companyTitleMapper.selectByTaxId(buyerName);
- if (existingTitle == null) {
- String errorInfo = String.format("发票: %s, 购买方名称: %s, 税号: %s",
- fileName, buyerName, buyerTaxId);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 税号={} 不存在于抬头库, 文件名={}", buyerTaxId, fileName);
- }
- } else {
- String errorInfo = String.format("发票: %s, 购买方税号为空", fileName);
- invalidBuyerTaxIds.add(errorInfo);
- log.warn("抬头校验失败: 购买方税号为空, 文件名={}", fileName);
- }
- // ========== 校验2:发票号重复校验(与数据库中的发票号比较) ==========
- if (StringUtils.isNotBlank(invoiceNumber)) {
- // 检查数据库中是否已存在相同的发票号
- LambdaQueryWrapper<InvoiceLibrary> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(InvoiceLibrary::getInvoiceNumber, invoiceNumber);
- InvoiceLibrary existingInvoice = baseMapper.selectOne(queryWrapper);
- if (existingInvoice != null) {
- String errorMsg = String.format("发票号重复: %s (当前文件: %s, 已存在于OA审批单: %s)",
- invoiceNumber, fileName, existingInvoice.getOaId());
- log.error(errorMsg);
- // 终止流程并回写原因
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- // 同时检查同一审批单内是否有重复(防止同一单据内上传重复发票)
- if (invoiceNumberList.contains(invoiceNumber)) {
- String errorMsg = String.format("当前审批单内发票号重复: %s (当前文件: %s, 已存在文件: %s)",
- invoiceNumber, fileName, invoiceNumberToFileName.get(invoiceNumber));
- log.error(errorMsg);
- // 终止流程并回写原因
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- invoiceNumberList.add(invoiceNumber);
- invoiceNumberToFileName.put(invoiceNumber, fileName);
- }
- } else {
- log.warn("发票解析结果为空: fileName={}", fileName);
- }
- } else {
- log.warn("发票OCR识别结果为空: fileName={}", fileName);
- }
- } catch (Exception e) {
- log.error("发票解析异常: fileId={}, fileName={}", fileId, fileName, e);
- String errorMsg = "发票解析失败: " + e.getMessage();
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- }
- } else {
- log.warn("附件列表为空");
- return McR.error("400", "请上传发票附件");
- }
- // ========== 抬头校验失败处理 ==========
- if (!invalidBuyerTaxIds.isEmpty()) {
- String errorMsg = "发票抬头有误,以下发票的购买方税号不在公司抬头库中:\n" + String.join("\n", invalidBuyerTaxIds);
- log.error(errorMsg);
- // 终止流程
- terminateWorkflow(accessToken, processInstanceId, userId, errorMsg);
- return McR.error("400", errorMsg);
- }
- BigDecimal totalAmount = BigDecimal.ZERO;
- // ========== 第二遍遍历:保存发票数据(校验通过后) ==========
- for (Map<String, Object> parsedData : parsedInvoiceDataList) {
- JSONObject invoice = (JSONObject) parsedData.get("invoice");
- Object responseData = parsedData.get("responseData");
- allResults.add(responseData);
- BigDecimal amount = invoice.getBigDecimal("amount");
- if (amount != null) {
- totalAmount = totalAmount.add(amount);
- }
- // 构建InvoiceLibrary对象
- InvoiceLibrary invoiceLibrary = new InvoiceLibrary();
- invoiceLibrary.setOaId(processInstanceId);
- invoiceLibrary.setInvoiceCode(invoice.getString("code") != null ? invoice.getString("code") : "");
- invoiceLibrary.setInvoiceNumber(invoice.getString("serial") != null ? invoice.getString("serial") : "");
- invoiceLibrary.setInvoiceType(invoice.getString("kindName") != null ? invoice.getString("kindName") : "");
- String date = invoice.getString("date");
- if (StringUtils.isNotBlank(date)) {
- try {
- invoiceLibrary.setInvoiceDate(LocalDate.parse(date.trim()));
- } catch (Exception e) {
- log.warn("日期解析失败: {}", date, e);
- }
- }
- invoiceLibrary.setAmount(invoice.getBigDecimal("excludingTax") != null ? invoice.getBigDecimal("excludingTax") : BigDecimal.ZERO);
- invoiceLibrary.setTaxAmount(invoice.getBigDecimal("tax") != null ? invoice.getBigDecimal("tax") : BigDecimal.ZERO);
- invoiceLibrary.setTotalAmount(invoice.getBigDecimal("amount") != null ? invoice.getBigDecimal("amount") : BigDecimal.ZERO);
- invoiceLibrary.setBuyerName(invoice.getString("buyerName") != null ? invoice.getString("buyerName") : "");
- invoiceLibrary.setBuyerTaxId(invoice.getString("buyerTaxId") != null ? invoice.getString("buyerTaxId") : "");
- invoiceLibrary.setSellerName(invoice.getString("sellerName") != null ? invoice.getString("sellerName") : "");
- invoiceLibrary.setSellerTaxId(invoice.getString("sellerTaxId") != null ? invoice.getString("sellerTaxId") : "");
- invoiceLibrary.setOaStatus("0");
- invoiceLibrary.setInvoiceStatus("0");
- invoiceLibrary.setDep(bm != null ? bm : "");
- invoiceLibrary.setAccountTitle(bxlb != null ? bxlb : "");
- invoiceLibrary.setPayAmount(mainJe != null ? mainJe : BigDecimal.ZERO);
- invoiceLibrary.setCreatedAt(LocalDateTime.now());
- invoiceLibrary.setUpdatedAt(LocalDateTime.now());
- invoiceLibrary.setFormName("批量付款申请(一对多)");
- invoiceLibrary.setPaySubject(fkzhxx != null ? fkzhxx : "");
- invoiceLibrary.setPayAccount(fkzh != null ? fkzh : "");
- invoiceLibrary.setBankName(yhqc != null ? yhqc : "");
- invoiceLibrary.setIsLongTerm(sfct != null ? sfct : "");
- invoiceList.add(invoiceLibrary);
- }
- // 保存发票记录
- if (!invoiceList.isEmpty()) {
- for (InvoiceLibrary invoice : invoiceList) {
- baseMapper.insert(invoice);
- }
- log.info("成功保存 {} 条发票记录", invoiceList.size());
- } else {
- log.warn("没有有效的发票数据可保存");
- }
- addWorkflowComment1(processInstanceId, userId, totalAmount);
- return McR.success(allResults);
- } catch (Exception e) {
- log.error("解析子表数据失败", e);
- return McR.error("300", "解析数据失败: " + e.getMessage());
- }
- }
- }
- }
- return McR.success();
- } catch (Exception e) {
- log.error("处理审批实例失败", e);
- return McR.error("500", "系统处理失败: " + e.getMessage());
- }
- }
- @Override
- public void updateSfctByOaId(Map map) {
- try {
- String oaId = UtilMap.getString(map, "oaId");
- String sfct = UtilMap.getString(map, "sfct");
- String fkzhxx = UtilMap.getString(map, "fkzhxx");
- String fkzh = UtilMap.getString(map, "fkzh");
- String yhqc = UtilMap.getString(map, "yhqc");
- sfct = (sfct == null || sfct.trim().isEmpty()) ? "否" : sfct;
- // 创建更新条件
- LambdaUpdateWrapper<InvoiceLibrary> updateWrapper = new LambdaUpdateWrapper<>();
- updateWrapper.eq(InvoiceLibrary::getOaId, oaId)
- .set(InvoiceLibrary::getIsLongTerm, sfct)
- .set(InvoiceLibrary::getPayAccount, fkzh)
- .set(InvoiceLibrary::getBankName, yhqc)
- .set(InvoiceLibrary::getPaySubject, fkzhxx)
- .set(InvoiceLibrary::getUpdatedAt, LocalDateTime.now());
- int updateCount = baseMapper.update(null, updateWrapper);
- if (updateCount > 0) {
- log.info("更新成功: 共更新{}条记录", updateCount);
- } else {
- log.warn("未找到符合条件的记录: oaId={}", oaId);
- }
- } catch (Exception e) {
- throw new RuntimeException("更新OA状态失败", e);
- }
- }
- /**
- * 添加钉钉审批评论
- */
- private void addWorkflowComment(String processInstanceId, String userId, Object totalAmount) {
- try {
- Map<String, Object> body = new HashMap<>();
- body.put("processInstanceId", processInstanceId);
- body.put("text", totalAmount);
- body.put("commentUserId", userId);
- String result = UtilHttp.doPost(
- "https://api.dingtalk.com/v1.0/workflow/processInstances/comments",
- ddClient.initTokenHeader(),
- null,
- body
- );
- log.info("添加审批评论成功: {}", result);
- } catch (Exception e) {
- log.error("添加审批评论失败", e);
- }
- }
- private void addWorkflowComment1(String processInstanceId, String userId, BigDecimal totalAmount) {
- try {
- Map<String, Object> body = new HashMap<>();
- body.put("processInstanceId", processInstanceId);
- body.put("text", "发票总金额:"+totalAmount);
- body.put("commentUserId", userId);
- String result = UtilHttp.doPost(
- "https://api.dingtalk.com/v1.0/workflow/processInstances/comments",
- ddClient.initTokenHeader(),
- null,
- body
- );
- log.info("添加审批评论成功: {}", result);
- } catch (Exception e) {
- log.error("添加审批评论失败", e);
- }
- }
- /**
- * 从 Map 中获取字符串值
- */
- private String getStringValue(Map<String, Object> map, String key) {
- Object value = map.get(key);
- return value != null ? String.valueOf(value) : "";
- }
- /**
- * 从 Map 中获取 BigDecimal 值
- */
- private BigDecimal getBigDecimalValue(Map<String, Object> map, String key) {
- Object value = map.get(key);
- if (value == null) {
- return BigDecimal.ZERO;
- }
- if (value instanceof BigDecimal) {
- return (BigDecimal) value;
- }
- try {
- return new BigDecimal(String.valueOf(value));
- } catch (NumberFormatException e) {
- return BigDecimal.ZERO;
- }
- }
- /**
- * 空字符串转换
- */
- private String nullToEmpty(String str) {
- return str != null ? str : "";
- }
- private void downloadDdFile(String processInstanceId, String fileId, String downloadPath) {
- try {
- Map body = new HashMap();
- body.put("processInstanceId", processInstanceId);
- body.put("fileId", fileId);
- DDR_New ddrNew = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v1.0/workflow/processInstances/spaces/files/urls/download", ddClient.initTokenHeader(), null, body, DDR_New.class);
- //2、执行下载
- Map result = (Map) ddrNew.getResult();
- String downloadUri = UtilMap.getString(result, "downloadUri");
- downloadFile(downloadUri, downloadPath);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- //文件下载到本地
- private void downloadFile(String downloadUri, String downloadPath) {
- try {
- URL url = new URL(downloadUri);
- HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
- int responseCode = httpConn.getResponseCode();
- // 检查HTTP响应代码是否为200
- if (responseCode == HttpURLConnection.HTTP_OK) {
- InputStream inputStream = httpConn.getInputStream();
- FileOutputStream outputStream = new FileOutputStream(downloadPath);
- byte[] buffer = new byte[4096];
- int bytesRead = -1;
- while ((bytesRead = inputStream.read(buffer)) != -1) {
- outputStream.write(buffer, 0, bytesRead);
- }
- outputStream.close();
- inputStream.close();
- } else {
- System.out.println("无法下载文件。HTTP响应代码: " + responseCode);
- }
- httpConn.disconnect();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- /**
- * 私有化方法:混票识别处理
- *
- * @param data 包含url、size、isPdf的Map参数
- * @return 识别结果
- */
- private McR<Object> processMixedInvoice(Map<String, Object> data) throws TencentCloudSDKException {
- McException.assertParamException_Null(data, "url");
- String image = String.valueOf(data.get("url"));
- log.info("混票识别, 免登地址, {}", image);
- // 非PDF, 且内存大于3M, 压缩后上传
- if (UtilMap.getFloat(data, "size") > 3.0f && !UtilMap.getBoolean(data, "isPdf")) {
- image = imageUrlConvertBase64(image);
- }
- if (UtilMap.getFloat(data, "size") > 6.0f && UtilMap.getBoolean(data, "isPdf")) {
- image = pdfUrlConvertBase64(image);
- }
- List<Map> invoices = (List<Map>) txyInvoice.doRecognizeGeneralInvoice(image).get("MixedInvoiceItems");
- System.out.println("invoices=====" + invoices);
- List<String> nos = new ArrayList<>();
- List<McInvoiceDto> result = invoices.stream().map(item -> {
- Map prop = UtilMap.getMap(UtilMap.getMap(item, "SingleInvoiceInfos"), UtilMap.getString(item, "SubType"));
- String taxRate = null;
- // List<Map<String, Object>> vatInvoiceItemInfos = UtilMap.getList(prop, "VatInvoiceItemInfos");
- // 优先使用 VatInvoiceItemInfos,如果为空则使用 VatElectronicItems
- List<Map<String, Object>> vatInvoiceItemInfos =
- UtilMap.getList(prop, "VatInvoiceItemInfos") != null && !UtilMap.getList(prop, "VatInvoiceItemInfos").isEmpty()
- ? UtilMap.getList(prop, "VatInvoiceItemInfos")
- : UtilMap.getList(prop, "VatElectronicItems");
- // if (!vatInvoiceItemInfos.isEmpty()) {
- // taxRate = UtilMap.getString(vatInvoiceItemInfos.get(0), "TaxRate");
- // }
- if (!vatInvoiceItemInfos.isEmpty()) {
- String originalTaxRate = UtilMap.getString(vatInvoiceItemInfos.get(0), "TaxRate");
- // 判断是否为有效数字(包括带%号的格式,如"9%")
- if (StringUtils.isNotBlank(originalTaxRate)) {
- // 移除百分号并尝试解析为数字
- String cleanedTaxRate = originalTaxRate.replace("%", "").trim();
- try {
- // 尝试转换为数字
- new BigDecimal(cleanedTaxRate);
- taxRate = originalTaxRate; // 保持原值(可能带%)
- } catch (NumberFormatException e) {
- // 如果不是数字(如"不征税"、"免税"等),赋值为"0"
- taxRate = "0";
- log.debug("税率格式异常,原始值: {}, 已设置为0", originalTaxRate);
- }
- } else {
- taxRate = "0";
- }
- } else {
- taxRate = "0";
- }
- String no = UtilMap.getString(prop, "Number");
- if (nos.contains(no)) {
- return null;
- }
- nos.add(no);
- String kind = UtilMap.getString(item, "TypeDescription");
- String invoiceName = UtilMap.getString(item, "SubTypeDescription");
- if (kind.equals("全电发票")) {
- if (invoiceName.contains("铁路电子客票")) {
- kind = "火车票";
- } else if (invoiceName.contains("机票行程单")) {
- kind = "机票行程单";
- } else if (invoiceName.contains("专用发票")) {
- kind = "全电专用发票";
- } else {
- kind = "全电普通发票";
- }
- }
- if (kind.equals("增值税发票")) {
- if (invoiceName.contains("区块链电子发票")) {
- kind = "区块链电子发票";
- } else if (invoiceName.contains("增值税专用发票")) {
- kind = "增值税专用发票";
- } else if (invoiceName.contains("增值税普通发票")) {
- kind = "增值税普通发票";
- } else if (invoiceName.contains("增值税电子专用发票")) {
- kind = "增值税电子专用发票";
- } else if (invoiceName.contains("增值税电子普通发票")) {
- kind = "增值税电子普通发票";
- } else {
- kind = "增值税普通发票";
- }
- }
- McInvoiceDto invoiceDto = McInvoiceDto.builder()
- .name(UtilMap.getString(item, "SubTypeDescription"))
- .kindName(kind)
- .kind(UtilMap.getInt(item, "Type"))
- .taxRate(taxRate)
- .code(UtilMap.getString(prop, "Code"))
- .serial(UtilMap.getString(prop, "Number"))
- .date(UtilString.replaceDateZH_cn(UtilMap.getString(prop, "Date")))
- .checkCode(UtilMap.getString(prop, "CheckCode"))
- .amount(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "Total", "Fare")))
- .tax(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "Tax")))
- .excludingTax(UtilNumber.setBigDecimal(UtilMap.getString(prop, "PretaxAmount")))
- .buyerName(StringUtils.defaultString(guyuanNameRepalce(UtilMap.getString(prop, "Buyer"))))
- .buyerTaxId(StringUtils.isBlank(UtilMap.getString(prop, "BuyerTaxID"))
- ? "" : UtilMap.getString(prop, "BuyerTaxID"))
- .sellerName(guyuanNameRepalce(UtilMap.getString_first(prop, "Seller", "Issuer")))
- .sellerTaxId(UtilMap.getString_first(prop, "SellerTaxID", "AgentCode"))
- .passengerName(UtilMap.getString_first(prop, "Name", "UserName"))
- .seatType(UtilMap.getString(prop, "Seat"))
- .departureTime(UtilString.replaceDateZH_cn(UtilMap.getString(prop, "DateGetOn"))
- + " " + UtilMap.getString(prop, "TimeGetOn"))
- .departurePort(UtilMap.getString_first(prop, "StationGetOn", "Entrance", "Place"))
- .arrivePort(UtilMap.getString_first(prop, "StationGetOff", "Exit"))
- .trainNo(UtilMap.getString_first(prop, "TrainNumber", "LicensePlate"))
- .insuranceCosts(UtilNumber.setBigDecimal(UtilMap.getString(prop, "Insurance")))
- .fuelCosts(UtilNumber.setBigDecimal(UtilMap.getString(prop, "FuelSurcharge")))
- .constructionCosts(UtilNumber.setBigDecimal(UtilMap.getString(prop, "AirDevelopmentFund")))
- .build();
- if ("机票行程单".equals(kind)) {
- invoiceDto.setSellerName(UtilMap.getString_first(prop, "Issuer"));
- invoiceDto.setSellerTaxId(UtilMap.getString_first(prop, "Seller"));
- Map flight = (Map) UtilMap.getList(prop, "FlightItems").get(0);
- invoiceDto.setDepartureTime(UtilString.replaceDateZH_cn(UtilMap.getString(item, "DateGetOn"))
- + " " + UtilMap.getString(prop, "TimeGetOn"));
- invoiceDto.setDeparturePort(UtilMap.getString(flight, "StationGetOn"));
- invoiceDto.setArrivePort(UtilMap.getString(flight, "StationGetOff"));
- invoiceDto.setSeatType(UtilMap.getString(flight, "Seat"));
- }
- if ("出租车发票".equals(item.get("TypeDescription"))) {
- invoiceDto.setDepartureTime(UtilMap.getString(prop, "TimeGetOn")
- + " ~ " + UtilMap.getString(prop, "TimeGetOff"));
- }
- return invoiceDto;
- }).filter(Objects::nonNull).collect(Collectors.toList());
- return McR.success(McInvoiceDto.formatResponse(result));
- }
- private static String guyuanNameRepalce(String name) {
- name = name.replaceAll(" ", "");
- if (name.contains("谷元")) {
- return UtilString.replaceBracketIsWhole(name);
- } else {
- return UtilString.replaceBracketIsSemiangle(name);
- }
- }
- /// url压缩转base64
- @SneakyThrows
- private String imageUrlConvertBase64(String imageUrl) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- // scale(比例), outputQuality(质量)
- Thumbnails.fromURLs(Arrays.asList(new URL(imageUrl))).scale(0.5f).outputQuality(0.25f).toOutputStream(out);
- InputStream inputStream = new ByteArrayInputStream(out.toByteArray());
- //转换为base64
- byte[] bytes = IOUtils.toByteArray(inputStream);
- return Base64.getEncoder().encodeToString(bytes);
- }
- @SneakyThrows
- private String pdfUrlConvertBase64(String pdfUrl) {
- String fileName = "tmp_" + new Date().getTime() + ".pdf";
- // 下载文件
- File file = UtilFile.mkdirIfNot(fileName, filePath.getPath().getTmp());
- UtilHttp.doDownload(pdfUrl, file);
- // PDF压缩
- PdfDocument doc = new PdfDocument(); // 创建PdfDocument类的对象
- doc.loadFromFile(file.getAbsolutePath()); // 加载PDF文档
- doc.getFileInfo().setIncrementalUpdate(false); // 禁用增量更新
- doc.setCompressionLevel(PdfCompressionLevel.Normal); // 将压缩级别设置为最佳
- // 遍历文档页面
- for (int i = 0; i < doc.getPages().getCount(); i++) {
- PdfPageBase page = doc.getPages().get(i); // 获取指定页面
- PdfImageInfo[] images = page.getImagesInfo(); // 获取每个页面的图像信息集合
- // 遍历集合中的所有项目
- if (images != null && images.length > 0)
- for (int j = 0; j < images.length; j++) {
- PdfImageInfo image = images[j]; // 获取指定图片
- PdfBitmap bp = new PdfBitmap(image.getImage());
- bp.setQuality(30); // 设置压缩质量
- page.replaceImage(j, bp); // 将原始图像替换为压缩图像
- }
- }
- // 将结果文档保存至另一个PDF文档中: 覆盖
- doc.saveToFile(file.getAbsolutePath());
- doc.close();
- // PDF转base64, 无需透出本地文件地址
- String base64 = UtilFile.fileToBase64(file.getAbsolutePath());
- // 删除临时PDF文件
- UtilFile.deleteFile(file.getAbsolutePath());
- return base64;
- }
- @GetMapping("/files/{fileId}")
- public ResponseEntity<Resource> getFileResource(
- @PathVariable String fileId,
- @RequestParam(defaultValue = "download") String option) throws IOException {
- // 根据fileId获取实际文件路径,这里简化处理,实际可能需要从数据库查询
- Path filePath = Paths.get("D://qiwang//files//").resolve(fileId).normalize();
- // 检查文件是否存在
- if (!Files.exists(filePath)) {
- return ResponseEntity.notFound().build();
- }
- // 创建Resource对象
- Resource resource = new UrlResource(filePath.toUri());
- // 根据选项设置响应头
- HttpHeaders headers = new HttpHeaders();
- if ("preview".equalsIgnoreCase(option)) {
- // 预览模式 - 尝试确定内容类型
- String contentType = Files.probeContentType(filePath);
- // 强制修正 PDF 的 Content-Type
- if (filePath.toString().toLowerCase().endsWith(".pdf")) {
- contentType = "application/pdf";
- } else if (contentType == null) {
- contentType = "application/octet-stream";
- }
- headers.setContentType(MediaType.parseMediaType(contentType));
- headers.add("Content-Disposition", "inline; filename=\"" + resource.getFilename() + "\"");
- headers.add("X-Content-Type-Options", "nosniff"); // 防止浏览器忽略 Content-Type
- } else {
- // 下载模式 - 默认处理
- headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
- headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"");
- }
- return ResponseEntity.ok()
- .headers(headers)
- .contentLength(resource.contentLength())
- .body(resource);
- }
- }
|