Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ zip/sample:
zip -r testdata.zip testdata

put/sample: zip/sample
wrangler r2 object delete $(BUCKET_NAME)/testdata.zip
wrangler r2 object put $(BUCKET_NAME)/testdata.zip --file testdata.zip
wrangler r2 object delete $(BUCKET_NAME)/testdata.zip --remote
wrangler r2 object put $(BUCKET_NAME)/testdata.zip --file testdata.zip --remote

get/sample: clean/data
mkdir -p $(DATA_DIR)
Expand Down
67 changes: 61 additions & 6 deletions internal/toukibo/houjin_body.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package toukibo

import "fmt"
import (
"fmt"
"strings"
)

type HoujinBody struct {
HoujinNumber string
Expand Down Expand Up @@ -43,6 +46,49 @@ func (h *HoujinBody) GetHoujinKaku() HoujinkakuType {
return h.HoujinKaku
}

func postProcessResponsibilityChangesGlobal(evsArr []HoujinExecutiveValue) {
// 1. ResignedAtに「責任変更」が含まれている役員を無効化
for i := range evsArr {
if !evsArr[i].IsValid {
continue
}

if strings.Contains(evsArr[i].ResignedAt, "責任変更") {
evsArr[i].IsValid = false
if DebugOn {
fmt.Printf("Invalidating (resigned): %s %s\n", evsArr[i].Name, evsArr[i].Position)
}
}
}

// 2. 無限責任社員と有限責任社員の同一人物がいる場合、有限責任社員を無効化
// (有限→無限への責任変更を想定)
for i := range evsArr {
if !evsArr[i].IsValid {
continue
}

if evsArr[i].Position == "無限責任社員" {
if DebugOn {
fmt.Printf("Found 無限責任社員: %s\n", evsArr[i].Name)
}
// 同じ名前の有限責任社員を探して無効化
for j := range evsArr {
if !evsArr[j].IsValid || i == j {
continue
}

if evsArr[j].Name == evsArr[i].Name && evsArr[j].Position == "有限責任社員" {
if DebugOn {
fmt.Printf("Invalidating 有限責任社員: %s (found matching 無限責任社員)\n", evsArr[j].Name)
}
evsArr[j].IsValid = false
}
}
}
}
}

func (h *HoujinBody) GetHoujinExecutives() ([]HoujinExecutiveValue, error) {
if len(h.HoujinExecutive) == 0 {
if h.HoujinDissolvedAt != "" {
Expand All @@ -52,14 +98,23 @@ func (h *HoujinBody) GetHoujinExecutives() ([]HoujinExecutiveValue, error) {
return []HoujinExecutiveValue{}, fmt.Errorf("not found executives")
}

var res []HoujinExecutiveValue
// まず全ての役員を集める
var all []HoujinExecutiveValue
for _, e := range h.HoujinExecutive {
for _, v := range e {
if v.IsValid {
res = append(res, v)
}
all = append(all, e...)
}

// 責任変更の後処理を全役員に対して実行
postProcessResponsibilityChangesGlobal(all)

// IsValidな役員のみを返す
var res []HoujinExecutiveValue
for _, v := range all {
if v.IsValid {
res = append(res, v)
}
}

if len(res) > 0 {
return res, nil
}
Expand Down
129 changes: 106 additions & 23 deletions internal/toukibo/parse_body.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ func getRegisterAt(s string) (string, error) {
}

func getResignedAt(s string) (string, error) {
// 辞任/退任の他に死亡、抹消、廃止、解任、退社も含める
date, found := ExtractDateWithSuffix(s, []string{"辞任", "退任", "死亡", "抹消", "廃止", "解任", "退社"})
// 辞任/退任の他に死亡、抹消、廃止、解任、退社、責任変更も含める
date, found := ExtractDateWithSuffix(s, []string{"辞任", "退任", "死亡", "抹消", "廃止", "解任", "退社", "責任変更"})
if found {
return trimAllSpace(date), nil
}
Expand Down Expand Up @@ -265,13 +265,13 @@ func applyDatesToExecutives(evs []HoujinExecutiveValue, three []string) {
}
}

func handlePreviousExecutiveRelation(evsArr HoujinExecutiveValueArray, idx int,
func handlePreviousExecutiveRelation(evsArr HoujinExecutiveValueArray, idx int,
currentEvs []HoujinExecutiveValue, three []string, registerAt, resignedAt string) {

if idx == 0 {
return
}

if len(currentEvs) == 0 {
// 役員がないのに登記日がある場合は前の役員を対象にする
if registerAt != "" {
Expand All @@ -281,42 +281,57 @@ func handlePreviousExecutiveRelation(evsArr HoujinExecutiveValueArray, idx int,
}
return
}

if len(currentEvs) == 1 {
handleSingleExecutive(evsArr, idx, currentEvs[0], three)
// 責任変更の場合、同一人物の過去の役職エントリも無効化
joinedThree := strings.Join(three, "")
if strings.Contains(joinedThree, "責任変更") {
for i := 0; i < idx; i++ {
if evsArr[i].Name == currentEvs[0].Name && evsArr[i].Position != currentEvs[0].Position {
evsArr[i].IsValid = false
}
}
}
}
}

func handleSingleExecutive(evsArr HoujinExecutiveValueArray, idx int,
func handleSingleExecutive(evsArr HoujinExecutiveValueArray, idx int,
currentEv HoujinExecutiveValue, three []string) {

prev := &evsArr[idx-1]

// 同一役員チェック
if prev.Name == currentEv.Name && prev.Position == currentEv.Position {
prev.IsValid = false
return
}

joinedThree := strings.Join(three, "")

// 重任チェック
if strings.Contains(joinedThree, "重任") && prev.Position == currentEv.Position {
prev.IsValid = false
return
}

// 氏名変更チェック
if isNameChange(joinedThree, prev.Name) {
prev.IsValid = false
return
}

// 更正チェック
if strings.Contains(joinedThree, "更正") {
prev.IsValid = false
return
}

// 責任変更チェック(同一人物で役職が変わった場合)
if strings.Contains(joinedThree, "責任変更") && prev.Name == currentEv.Name {
prev.IsValid = false
return
}
}

func isNameChange(text, name string) bool {
Expand Down Expand Up @@ -345,41 +360,109 @@ func GetHoujinExecutiveValue(s string) (HoujinExecutiveValueArray, error) {
parts := splitReverts(s)
evsArr := make(HoujinExecutiveValueArray, 0, len(parts))

var idx int
for _, p := range parts {
if DebugOn {
PrintSlice(ExtractLines(p))
}

// 役員情報の抽出
evs, three := extractExecutiveInfo(p)

// 日付情報の適用
applyDatesToExecutives(evs, three)

// 日付だけ抽出(前の役員処理用)
registerAt, resignedAt := extractDates(three)

// 前の役員との関係処理
handlePreviousExecutiveRelation(evsArr, idx, evs, three, registerAt, resignedAt)

currentIdx := len(evsArr)
handlePreviousExecutiveRelation(evsArr, currentIdx, evs, three, registerAt, resignedAt)

// 結果の更新
if len(evs) > 0 {
idx += len(evs)
evsArr = append(evsArr, evs...)
} else if idx > 0 && registerAt != "" {
} else if currentIdx > 0 && registerAt != "" {
// 役員がないのに登記日がある場合は前の役員処理は上で完了しているので、ここではスキップ
continue
}
}


// 後処理:責任変更があった場合、同一人物の過去の異なる役職を無効化
postProcessResponsibilityChanges(evsArr)

if DebugOn {
fmt.Println(evsArr)
}

return evsArr, nil
}

func postProcessResponsibilityChanges(evsArr HoujinExecutiveValueArray) {
// 1. ResignedAtに「責任変更」が含まれている役員を無効化
for i := range evsArr {
if !evsArr[i].IsValid {
continue
}

if strings.Contains(evsArr[i].ResignedAt, "責任変更") {
evsArr[i].IsValid = false
if DebugOn {
fmt.Printf("Invalidating (resigned): %s %s\n", evsArr[i].Name, evsArr[i].Position)
}
}
}

// 2. 無限責任社員と有限責任社員の同一人物がいる場合、有限責任社員を無効化
// (有限→無限への責任変更を想定)
for i := range evsArr {
if !evsArr[i].IsValid {
continue
}

if evsArr[i].Position == "無限責任社員" {
if DebugOn {
fmt.Printf("Found 無限責任社員: %s\n", evsArr[i].Name)
}
// 同じ名前の有限責任社員を探して無効化
for j := range evsArr {
if !evsArr[j].IsValid || i == j {
continue
}

if evsArr[j].Name == evsArr[i].Name && evsArr[j].Position == "有限責任社員" {
if DebugOn {
fmt.Printf("Invalidating 有限責任社員: %s (found matching 無限責任社員)\n", evsArr[j].Name)
}
evsArr[j].IsValid = false
}
}
}
}
}

func shouldInvalidateOldPosition(newer, older HoujinExecutiveValue) bool {
// 責任に関する役職変更のパターン
// 無限責任社員 vs 有限責任社員
// どちらかが社員系の役職で、もう一方も社員系の場合、古い方を無効化

isNewerShain := strings.Contains(newer.Position, "責任社員")
isOlderShain := strings.Contains(older.Position, "責任社員")

if isNewerShain && isOlderShain {
// 両方とも社員の場合、登記日を比較
// RegisterAtが設定されている場合は比較
if newer.RegisterAt != "" && older.RegisterAt != "" {
return newer.RegisterAt > older.RegisterAt
}
// 無限責任社員の方が新しいと仮定(有限→無限への変更が一般的)
if strings.Contains(newer.Position, "無限") && strings.Contains(older.Position, "有限") {
return true
}
}

return false
}

func (h *HoujinBody) ConsumeHoujinNumber(s string) bool {
// 正規表現パターン: 全角数字で構成された法人番号
pattern := "([0-9]{4}-[0-9]{2}-[0-9]{6})"
Expand Down
Loading