123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642 |
- package backend
- import (
- "context"
- "fmt"
- "kpt-pasture/model"
- "kpt-pasture/util"
- "net/http"
- "time"
- "gorm.io/gorm"
- "gitee.com/xuyiping_admin/pkg/xerr"
- pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
- )
- func (s *StoreEntry) DrugsList(ctx context.Context, req *pasturePb.SearchDrugsRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SearchDrugsResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- drugsList := make([]*model.Drugs, 0)
- var count int64 = 0
- pref := s.DB.Model(new(model.Drugs)).Where("pasture_id = ?", userModel.AppPasture.Id)
- if req.Name != "" {
- pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%"))
- }
- if req.Usage > 0 {
- pref.Where("usage_method = ?", req.Usage)
- }
- if req.CategoryId > 0 {
- pref.Where("category_id = ?", req.CategoryId)
- }
- if err = pref.Order("id desc").Count(&count).Limit(int(pagination.PageSize)).Offset(int(pagination.PageOffset)).
- Find(&drugsList).Error; err != nil {
- return nil, xerr.WithStack(err)
- }
- return &pasturePb.SearchDrugsResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.SearchDrugsData{
- List: model.DrugsSlice(drugsList).ToPB(),
- Total: int32(count),
- PageSize: pagination.PageSize,
- Page: pagination.Page,
- },
- }, nil
- }
- func (s *StoreEntry) DrugsCreateOrUpdate(ctx context.Context, req *pasturePb.SearchDrugsList) error {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return xerr.WithStack(err)
- }
- req.CategoryName = s.DrugCategoryMaps()[req.CategoryId]
- req.UnitName = s.UnitMap()[req.Unit]
- req.UsageName = s.DrugUsageMaps()[req.Usage]
- newDrugs := model.NewDrugs(userModel.AppPasture.Id, req, userModel.SystemUser)
- if req.Id <= 0 {
- if err = s.DB.Create(newDrugs).Error; err != nil {
- return xerr.WithStack(err)
- }
- } else {
- if err = s.DB.Where("id = ?", req.Id).Updates(newDrugs).Error; err != nil {
- return xerr.WithStack(err)
- }
- }
- return nil
- }
- func (s *StoreEntry) MedicalEquipmentList(ctx context.Context, req *pasturePb.SearchMedicalEquipmentRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SearchMedicalEquipmentResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- medicalEquipmentList := make([]*model.MedicalEquipment, 0)
- var count int64 = 0
- pref := s.DB.Model(new(model.MedicalEquipment)).Where("pasture_id = ?", userModel.AppPasture.Id)
- if req.Name != "" {
- pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%"))
- }
- if err = pref.Order("id desc").Count(&count).Limit(int(pagination.PageSize)).Offset(int(pagination.PageOffset)).
- Find(&medicalEquipmentList).Error; err != nil {
- return nil, xerr.WithStack(err)
- }
- unitMap := s.UnitMap()
- return &pasturePb.SearchMedicalEquipmentResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.SearchMedicalEquipmentData{
- List: model.MedicalEquipmentSlice(medicalEquipmentList).ToPB(unitMap),
- Total: int32(count),
- PageSize: pagination.PageSize,
- Page: pagination.Page,
- },
- }, nil
- }
- func (s *StoreEntry) MedicalEquipmentCreateOrUpdate(ctx context.Context, req *pasturePb.SearchMedicalEquipmentList) error {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return xerr.WithStack(err)
- }
- newDrugs := model.NewMedicalEquipment(userModel.AppPasture.Id, req, userModel.SystemUser)
- if req.Id <= 0 {
- if err = s.DB.Create(newDrugs).Error; err != nil {
- return xerr.WithStack(err)
- }
- } else {
- if err = s.DB.Where("id = ?", req.Id).Updates(newDrugs).Error; err != nil {
- return xerr.WithStack(err)
- }
- }
- return nil
- }
- func (s *StoreEntry) NeckRingCreateOrUpdate(ctx context.Context, req *pasturePb.NeckRingCreateRequest) error {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return xerr.WithStack(err)
- }
- if req.Items == nil || len(req.Items) == 0 {
- return xerr.Custom("请选择要脖环数据")
- }
- if err = s.DB.Transaction(func(tx *gorm.DB) error {
- for _, item := range req.Items {
- number := ""
- cowInfo, err := s.GetCowInfoByCowId(ctx, userModel.AppPasture.Id, int64(item.CowId))
- if err != nil {
- return xerr.Customf("该牛: %d 不存在", item.CowId)
- }
- newNeckRingLog := model.NewNeckRingBindLog(userModel.AppPasture.Id, item.Number, cowInfo, userModel.SystemUser)
- neckRing, ok, err := s.NeckRingIsExist(ctx, userModel.AppPasture.Id, item.Number)
- switch req.Status {
- case pasturePb.NeckRingOperationStatus_Bind: // 绑定
- if err != nil {
- return xerr.WithStack(err)
- }
- if ok && neckRing.Status == pasturePb.NeckRingStatus_Bind {
- return xerr.Customf("该脖环: %s已经绑定牛只: %s", item.Number, neckRing.EarNumber)
- }
- newNeckRing := model.NewNeckRing(userModel.AppPasture.Id, item.Number, cowInfo, userModel.SystemUser)
- if err = tx.Create(newNeckRing).Error; err != nil {
- return xerr.WithStack(err)
- }
- number = item.Number
- newNeckRingLog.OperationStatusName = "绑定"
- // 解绑
- case pasturePb.NeckRingOperationStatus_UnBind:
- if ok && neckRing.Status != pasturePb.NeckRingStatus_Bind {
- return xerr.Customf("该脖环: %s,未绑定牛只", item.Number)
- }
- if err = tx.Model(new(model.NeckRing)).
- Where("id = ?", neckRing.Id).
- Updates(map[string]interface{}{
- "cow_id": 0,
- "ear_number": "",
- "wear_at": 0,
- "status": pasturePb.NeckRingStatus_Unbind,
- }).Error; err != nil {
- return xerr.WithStack(err)
- }
- newNeckRingLog.OperationStatusName = "解绑"
- // 编辑
- case pasturePb.NeckRingOperationStatus_Edit:
- if err = tx.Model(new(model.NeckRing)).
- Where("neck_ring_number = ?", item.Number).
- Updates(map[string]interface{}{
- "cow_id": cowInfo.Id,
- "ear_number": cowInfo.EarNumber,
- "wear_at": time.Now().Unix(),
- "status": pasturePb.NeckRingStatus_Bind,
- }).Error; err != nil {
- return xerr.WithStack(err)
- }
- number = item.Number
- newNeckRingLog.OperationStatusName = "编辑"
- default:
- continue
- }
- if err = tx.Create(newNeckRingLog).Error; err != nil {
- return xerr.WithStack(err)
- }
- if err = tx.Model(new(model.Cow)).
- Where("id = ?", item.CowId).
- Update("neck_ring_number", number).
- Error; err != nil {
- return xerr.WithStack(err)
- }
- }
- return nil
- }); err != nil {
- return xerr.WithStack(err)
- }
- return nil
- }
- func (s *StoreEntry) NeckRingList(ctx context.Context, req *pasturePb.SearchNeckRingRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SearchNeckRingResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- neckRingLogList := make([]*model.NeckRing, 0)
- var count int64 = 0
- pref := s.DB.Table(fmt.Sprintf("%s as a", new(model.NeckRing).TableName())).
- Select("a.*,COALESCE(b.pen_name, '') AS pen_name").
- Joins("LEFT JOIN cow as b ON a.cow_id = b.id").
- Where("a.status >= ?", pasturePb.NeckRingStatus_Unbind).
- Where("a.pasture_id = ?", userModel.AppPasture.Id).
- Where("a.neck_ring_number != ''")
- if req.Status > 0 {
- pref.Where("a.status = ?", req.Status)
- }
- if req.CowId > 0 {
- pref.Where("a.cow_id = ?", req.CowId)
- }
- if req.Number != "" {
- pref.Where("a.number like ?", fmt.Sprintf("%s%s%s", "%", req.Number, "%"))
- }
- if err = pref.Order("a.id desc").
- Count(&count).
- Limit(int(pagination.PageSize)).
- Offset(int(pagination.PageOffset)).
- Find(&neckRingLogList).Error; err != nil {
- return nil, xerr.WithStack(err)
- }
- neckRingStatusMap := s.NeckRingStatusMap()
- return &pasturePb.SearchNeckRingResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.SearchNeckRingData{
- List: model.NeckRingSlice(neckRingLogList).ToPB(neckRingStatusMap),
- Total: int32(count),
- PageSize: pagination.PageSize,
- Page: pagination.Page,
- },
- }, nil
- }
- func (s *StoreEntry) OutboundApply(ctx context.Context, req *pasturePb.OutboundApplyItem) error {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return xerr.WithStack(err)
- }
- if len(req.Goods) <= 0 {
- return xerr.Custom("请选择要出库商品")
- }
- var outbound *model.Outbound
- if req.Id > 0 {
- outbound, err = s.GetOutboundById(ctx, userModel.AppPasture.Id, int64(req.Id))
- if err != nil || outbound == nil || outbound.Id <= 0 {
- return xerr.Customf("该出库单不存在")
- }
- if userModel.SystemUser.Id != int64(outbound.ApplicantId) {
- return xerr.Custom("非申请人,无权修改该出库单")
- }
- if outbound.AuditStatus != pasturePb.AuditStatus_Pending {
- return xerr.Custom("该出库单不能修改")
- }
- } else {
- // 创建出库申请
- outbound = model.NewOutbound(userModel.AppPasture.Id, req, userModel.SystemUser)
- }
- goodsItems := make([]*pasturePb.OutboundApplyGoodsItem, 0)
- switch req.OutType {
- case pasturePb.OutType_Drugs:
- for _, v := range req.Goods {
- if v.Quantity <= 0 {
- return xerr.Custom("请填写商品数量")
- }
- if v.GoodsId <= 0 {
- return xerr.Custom("请选择要出库商品")
- }
- newDrugs := &model.Drugs{}
- if err = s.DB.Model(new(model.Drugs)).
- Where("id = ?", v.GoodsId).
- Where("inventory >= ?", v.Quantity).
- First(newDrugs).Error; err != nil {
- return xerr.WithStack(err)
- }
- goodsItems = append(goodsItems, &pasturePb.OutboundApplyGoodsItem{
- GoodsId: v.GoodsId,
- Quantity: v.Quantity,
- Unit: v.Unit,
- GoodsName: newDrugs.Name,
- Specs: newDrugs.Specs,
- Producer: newDrugs.Producer,
- BatchNumber: newDrugs.BatchNumber,
- Price: float32(newDrugs.Price) / 100,
- })
- }
- case pasturePb.OutType_Medical_Equipment:
- for _, v := range req.Goods {
- if v.Quantity <= 0 {
- return xerr.Custom("请填写商品数量")
- }
- if v.GoodsId <= 0 {
- return xerr.Custom("请选择要出库商品")
- }
- newMedicalEquipment := &model.MedicalEquipment{}
- if err = s.DB.Model(new(model.Drugs)).
- Where("id = ?", v.GoodsId).
- Where("inventory >= ?", v.Quantity).
- First(newMedicalEquipment).Error; err != nil {
- return xerr.WithStack(err)
- }
- goodsItems = append(goodsItems, &pasturePb.OutboundApplyGoodsItem{
- GoodsId: v.GoodsId,
- Quantity: v.Quantity,
- Unit: v.Unit,
- GoodsName: newMedicalEquipment.Name,
- Specs: newMedicalEquipment.Specs,
- Producer: newMedicalEquipment.Producer,
- BatchNumber: newMedicalEquipment.BatchNumber,
- Price: float32(newMedicalEquipment.Price) / 100,
- })
- }
- default:
- return xerr.Custom("未知的出库类型")
- }
- unitMap := s.UnitMap()
- if err = s.DB.Transaction(func(tx *gorm.DB) error {
- if req.Id > 0 {
- if err = tx.Model(new(model.Outbound)).
- Where("id = ?", req.Id).
- Update("applicant_remarks", req.ApplicantRemarks).Error; err != nil {
- return xerr.WithStack(err)
- }
- if err = tx.Model(new(model.OutboundDetail)).
- Where("outbound_id = ?", req.Id).
- Update("is_delete = ?", pasturePb.IsShow_No).Error; err != nil {
- return xerr.WithStack(err)
- }
- } else {
- if err = tx.Create(outbound).Error; err != nil {
- return xerr.WithStack(err)
- }
- }
- outboundLog := model.NewOutboundDetailList(outbound.Id, goodsItems, unitMap)
- if err = tx.Create(outboundLog).Error; err != nil {
- return xerr.WithStack(err)
- }
- return nil
- }); err != nil {
- return xerr.WithStack(err)
- }
- return nil
- }
- func (s *StoreEntry) OutboundList(ctx context.Context, req *pasturePb.SearchOutboundApplyRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SearchOutboundApplyResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- startUnix := util.TimeParseLocalUnix(req.StartDayTime)
- endUnix := util.TimeParseLocalEndUnix(req.EndDayTime)
- var count int64 = 0
- outboundList := make([]*model.Outbound, 0)
- pref := s.DB.Model(new(model.Outbound)).Where("pasture_id = ?", userModel.AppPasture.Id)
- if req.OutType > 0 {
- pref.Where("out_type = ?", req.OutType)
- }
- if startUnix > 0 && endUnix > 0 && startUnix <= endUnix {
- pref.Where("applicant_at BETWEEN ? AND ?", startUnix, endUnix)
- }
- if req.Number != "" {
- pref.Where("number like ?", fmt.Sprintf("%s%s%s", "%", req.Number, "%"))
- }
- if req.AuditStatus > 0 {
- pref.Where("audit_status = ?", req.AuditStatus)
- }
- if req.ApplicantId > 0 {
- pref.Where("applicant_id = ?", req.ApplicantId)
- }
- if req.ExamineId > 0 {
- pref.Where("examine_id = ?", req.ExamineId)
- }
- if err = pref.Order("id desc").
- Count(&count).
- Limit(int(pagination.PageSize)).
- Offset(int(pagination.PageOffset)).
- Find(&outboundList).Error; err != nil {
- return nil, xerr.WithStack(err)
- }
- outTypeMap := s.OutTypeMap()
- auditStatusMap := s.AuditStatusMap()
- return &pasturePb.SearchOutboundApplyResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.SearchOutboundApplyData{
- List: model.OutboundSlice(outboundList).ToPB(outTypeMap, auditStatusMap),
- Total: int32(count),
- PageSize: pagination.PageSize,
- Page: pagination.Page,
- },
- }, nil
- }
- func (s *StoreEntry) OutboundAudit(ctx context.Context, req *pasturePb.OutboundApplyAuditRequest) error {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return xerr.WithStack(err)
- }
- outbound, err := s.GetOutboundById(ctx, userModel.AppPasture.Id, int64(req.Id))
- if err != nil {
- return xerr.WithStack(err)
- }
- if outbound == nil {
- return xerr.Custom("出库单不存在")
- }
- if req.AuditStatus != pasturePb.AuditStatus_Pass && req.AuditStatus != pasturePb.AuditStatus_Reject && req.AuditStatus != pasturePb.AuditStatus_Cancel {
- return xerr.Custom("审核状态异常")
- }
- if outbound.AuditStatus != pasturePb.AuditStatus_Pending {
- return xerr.Custom("异常出库单")
- }
- outboundDetails, err := s.GetOutboundDetailByOutboundId(ctx, outbound.Id)
- if err != nil {
- return xerr.WithStack(err)
- }
- if len(outboundDetails) <= 0 {
- return xerr.Custom("出库单商品不存在")
- }
- if err = s.DB.Transaction(func(tx *gorm.DB) error {
- if err = tx.Model(outbound).
- Where("id = ?", outbound.Id).
- Updates(map[string]interface{}{
- "audit_status": req.AuditStatus,
- "examine_id": userModel.SystemUser.Id,
- "examine_name": userModel.SystemUser.Name,
- "examine_remarks": req.ExamineRemarks,
- "examine_at": time.Now().Unix(),
- }).Error; err != nil {
- return xerr.WithStack(err)
- }
- if req.AuditStatus != pasturePb.AuditStatus_Pass {
- return nil
- }
- tableName := ""
- switch outbound.OutType {
- case pasturePb.OutType_Drugs:
- tableName = new(model.Drugs).TableName()
- case pasturePb.OutType_Medical_Equipment:
- tableName = new(model.MedicalEquipment).TableName()
- default:
- return nil
- }
- for _, v := range outboundDetails {
- if err = tx.Table(tableName).
- Where("id = ?", v.GoodsId).
- Updates(map[string]interface{}{
- "inventory": gorm.Expr("inventory - ?", v.Quantity),
- }).Error; err != nil {
- return xerr.WithStack(err)
- }
- }
- return nil
- }); err != nil {
- return xerr.WithStack(err)
- }
- return nil
- }
- func (s *StoreEntry) OutboundDetail(ctx context.Context, id int64) (*pasturePb.OutboundDetailResponse, error) {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- outbound, err := s.GetOutboundById(ctx, userModel.AppPasture.Id, id)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- outboundLogs, err := s.GetOutboundDetailByOutboundId(ctx, id)
- if err != nil {
- return nil, xerr.WithStack(err)
- }
- outTypeMap := s.OutTypeMap()
- auditStatusMap := s.AuditStatusMap()
- applicantAtFormat, examineAtFormat := "", ""
- if outbound.ApplicantAt > 0 {
- applicantAtFormat = time.Unix(outbound.ApplicantAt, 0).Format(model.LayoutTime)
- }
- if outbound.ExamineAt > 0 {
- examineAtFormat = time.Unix(outbound.ExamineAt, 0).Format(model.LayoutTime)
- }
- return &pasturePb.OutboundDetailResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.OutboundApplyDetail{
- Id: int32(outbound.Id),
- Number: outbound.Number,
- OutType: outbound.OutType,
- OutTypeName: outTypeMap[outbound.OutType],
- AuditStatus: outbound.AuditStatus,
- AuditStatusName: auditStatusMap[outbound.AuditStatus],
- ApplicantName: outbound.ApplicantName,
- ApplicantRemarks: outbound.ApplicantRemarks,
- ExamineName: outbound.ExamineName,
- ExamineRemarks: outbound.ExamineRemarks,
- ApplicantAtFormat: applicantAtFormat,
- ExamineAtFormat: examineAtFormat,
- GoodsItem: &pasturePb.OutboundApplyItem{
- OutType: outbound.OutType,
- Goods: model.OutboundDetailSlice(outboundLogs).ToPB(),
- ApplicantRemarks: outbound.ApplicantRemarks,
- },
- },
- }, nil
- }
- func (s *StoreEntry) OutboundDelete(ctx context.Context, id int64) error {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return xerr.WithStack(err)
- }
- outbound, err := s.GetOutboundById(ctx, userModel.AppPasture.Id, id)
- if err != nil {
- return xerr.WithStack(err)
- }
- if outbound == nil {
- return xerr.Custom("出库单不存在")
- }
- if !(outbound.AuditStatus == pasturePb.AuditStatus_Pending || outbound.AuditStatus == pasturePb.AuditStatus_Cancel) {
- return xerr.Custom("出库单无法删除")
- }
- if userModel.SystemUser.Id != int64(outbound.ApplicantId) {
- return xerr.Custom("非申请人,无权删除出库单")
- }
- outbound.Delete()
- if err = s.DB.Model(new(model.Outbound)).
- Select("audit_status").
- Updates(outbound).Error; err != nil {
- return xerr.WithStack(err)
- }
- return nil
- }
- func (s *StoreEntry) FrozenSemenList(ctx context.Context, req *pasturePb.FrozenSemenRequest, pagination *pasturePb.PaginationModel) (*pasturePb.FrozenSemenResponse, error) {
- frozenSemenList := make([]*model.FrozenSemen, 0)
- var count int64 = 0
- pref := s.DB.Table(new(model.FrozenSemen).TableName())
- if req.BullId != "" {
- pref.Where("bull_id = ?", req.BullId)
- }
- if req.Producer != "" {
- pref.Where("producer = ?", req.Producer)
- }
- if err := pref.Order("id desc").
- Count(&count).Limit(int(pagination.PageSize)).
- Offset(int(pagination.PageOffset)).
- Find(&frozenSemenList).Error; err != nil {
- return nil, xerr.WithStack(err)
- }
- frozenSemenTypeMap := s.FrozenSemenTypeMap()
- unitMap := s.UnitMap()
- return &pasturePb.FrozenSemenResponse{
- Code: http.StatusOK,
- Msg: "ok",
- Data: &pasturePb.SearchFrozenSemenData{
- List: model.FrozenSemenSlice(frozenSemenList).ToPB(frozenSemenTypeMap, unitMap),
- Total: int32(count),
- PageSize: pagination.PageSize,
- Page: pagination.Page,
- },
- }, nil
- }
- func (s *StoreEntry) FrozenSemenCreate(ctx context.Context, req *pasturePb.SearchFrozenSemenList) error {
- userModel, err := s.GetUserModel(ctx)
- if err != nil {
- return xerr.WithStack(err)
- }
- req.CowKindName = s.CowKindMap()[req.CowKind]
- newFrozenSemen := model.NewFrozenSemen(userModel.AppPasture.Id, req, userModel.SystemUser)
- if err := s.DB.Create(newFrozenSemen).Error; err != nil {
- return xerr.WithStack(err)
- }
- return nil
- }
|