Merged in feature/tests (pull request #117)
Feature/tests * improvetests * generation * simplifiedtesting * simplifiedtesting * longfile
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
Start of Page No. = 1
|
||||
|
||||
Hello World!
|
||||
|
||||
|
||||
+62
-79
@@ -1,122 +1,81 @@
|
||||
Document Index
|
||||
Sample Company Name, Inc. 1ANCILLARY AGREEMENT 1
|
||||
WITNESSETH: 1
|
||||
SECTION 1 - DEFINITIONS 1
|
||||
SECTION 2 - OBLIGATIONS OF COMMUNITY 4
|
||||
SECTION 3 - OBLIGATIONS OF PROVIDER 5
|
||||
SECTION 4 - MAINTENANCE, RELEASE & ACCESS TO RECORDS 8
|
||||
SECTION 5 - COMPENSATION 9
|
||||
SECTION 6 - UTILIZATION MANAGEMENT AND QUALITY IMPROVEMENT PROGRAMS 12
|
||||
SECTION 7 - INSURANCE, INDEMNIFICATION & RELEASE 13
|
||||
SECTION 8 - DISPUTE RESOLUTION 14
|
||||
SECTION 9 - CONFIDENTIALITY 14
|
||||
SECTION 10 - TERM AND TERMINATION 15
|
||||
SECTION 11 - MISCELLANEOUS 17
|
||||
EXHIBIT A 21CONTRACTED PROVIDER DEMOGRAPHICS & LIST OF HEALTHCARE PROFESSIONALS 21
|
||||
EXHIBIT B-1 24
|
||||
COMPENSATION 24
|
||||
Compensation Notes: 24
|
||||
EXHIBIT B-2 25
|
||||
COMPENSATION 25
|
||||
Compensation Notes: 26
|
||||
EXHIBIT B-3 27
|
||||
COMPENSATION 27
|
||||
TEXAS MEDICAID COMPLIANCE ADDENDUM - PROVIDER 28
|
||||
SECTION 1 - DEFINITIONS 28
|
||||
SECTION 2 - OBLIGATIONS OF COMMUNITY 29
|
||||
SECTION 3 - OBLIGATIONS OF PROVIDER 29
|
||||
SECTION 4 - COMPENSATION 31
|
||||
SECTION 5 - DISPUTE RESOLUTION 34
|
||||
SECTION 6 - CONFIDENTIALITY 34
|
||||
SECTION 7 - FRAUD AND ABUSE 34
|
||||
SECTION 8 - INSURANCE 35
|
||||
SECTION 9 - LAWS, RULES AND REGULATIONS 35
|
||||
SECTION 10 - MEMBER COMMUNICATIONS 36
|
||||
SECTION 11 - PRIMARY CARE PHYSICIANS AND PRIMARY CARE PROVIDERS 36
|
||||
SECTION 12 - TERMINATION 36
|
||||
SECTION 13 - BEHAVIORAL HEALTH 37
|
||||
ADDITIONAL PROVISIONS SPECIFIC TO MEDICAID 37
|
||||
|
||||
|
||||
|
||||
Start of Page No. = 1
|
||||
|
||||
Sample Company Name, Inc.
|
||||
ANCILLARY AGREEMENT
|
||||
This Agreement is entered into and effective as of the date shown on the signature page ("Effective
|
||||
Date"), by and between Sample Company
|
||||
Name,
|
||||
Inc
|
||||
Date"), by and between Sample Company Name, Inc
|
||||
a Texas non-profit 501(c)(4) corporation licensed by
|
||||
the Texas Department of Insurance as a health maintenance organization in the State of Texas and its Affiliates
|
||||
(collectively "Community") and ABC Center
|
||||
("Contracted Provider").
|
||||
(Legal Name and DBA as It appoars on W-9)
|
||||
(Legal Name and DBA as a appears on W-9)
|
||||
WITNESSETH:
|
||||
WHEREAS, Community has its certificate of authority to operate as a health maintenance organization
|
||||
under Chapter 843 of the Texas Insurance Code, as amended;
|
||||
under Chapter 843 of the Texas insurance Code, as amended;
|
||||
WHEREAS, Contracted Provider is licensed or otherwise authorized to provide a health care service in
|
||||
this State, and qualified to provide Covered Services; and
|
||||
this State, and qualified to provide Covered Services and
|
||||
WHEREAS, Community wishes to enter into an agreement with Contracted Provider to provide or arrange
|
||||
for the provision of Covered Services to Members, and Contracted Provider wishes to enter into an agreement with
|
||||
Community to provide or arrange for the provision of Covered Services to Members.
|
||||
NOW, THEREFORE, for and in consideration of the premises and the mutual covenants and agreements
|
||||
herein contained, it is understood and agreed by and between the parties hereto as follows:
|
||||
Community to provide or arrange for the provision of Covered Services to Members
|
||||
NOW, THEREFORE for and in consideration of the premises and the mutual covenants and agreements
|
||||
herein contained it is understood and agreed by and between the parties hereto as follows:
|
||||
SECTION 1 - DEFINITIONS
|
||||
Many words and terms are capitalized throughout this Agreement to indicate that they are defined as set forth in this
|
||||
Section 1.
|
||||
1.1
|
||||
Accreditation Organization. Any organization, including but not limited to, URAC. the National
|
||||
Committee for Quality Assurance ("NCQA") or the Joint Commission, engaged in accrediting or certifying
|
||||
Community or any Participating Provider.
|
||||
1.2 Affiliate. A corporation, partnership or other legal entity (including without limitation any Payor)
|
||||
Accreditation Organization Any organization including but not limited to, URAC. the National
|
||||
Committee for Quality Assurance ("NCQA") or the Joint Commission engaged in accrediting or certifying
|
||||
Community or any Participating Provider
|
||||
1.2
|
||||
Affiliate A corporation partnership or other legal entity (including without limitation any Payor)
|
||||
directly or indirectly owned or controlled by, or which owns or controls, or which is under common ownership or
|
||||
control with Community.
|
||||
1,3
|
||||
Benefit Plan/Program. A certificate of coverage, summary plan description, or other document or
|
||||
program under which Community or other Payor undertakes to provide, arrange for, pay for, or reimburse any part
|
||||
of the cost of health care services for eligible Members. Community may also enter into administrative agreements
|
||||
1.3
|
||||
Benefit Plan/Program A certificate of coverage, summary plan description, or other document or
|
||||
program under which Community or other Payor undertakes to provide arrange for, pay for, or reimburse any part
|
||||
of the cost of health care services for eligible Members Community may also enter into administrative agreements
|
||||
with other Payors, governmental, public or private employers, or other entities to provide administrative services
|
||||
related to providing, arranging for, paying for or reimbursing for the cost of health care services, including self-funded
|
||||
employer sponsored plans. Benefit Plan/Program will include self-funded employee benefit plans for which
|
||||
Community provides administrative services.
|
||||
1.4
|
||||
Billed Charges. The usual and customary fee charged by Provider that does not exceed the fee
|
||||
Provider would ordinarily charge regardless of expected payment source.
|
||||
Provider would ordinarily charge regardless of expected payment source
|
||||
1.5
|
||||
Capitation. A method of compensating a Provider for arranging for or providing a defined set of
|
||||
Capitation A method of compensating a Provider for arranging for or providing a defined set of
|
||||
covered health care services to certain enrollees for a specified period that is based on a predetermined payment
|
||||
per enrollee for the specified period, without regard to the quantity of services actually provided.
|
||||
1.6
|
||||
CMS. The federal agency, Center for Medicare and Medicaid Services, responsible for
|
||||
administering the Medicare, Medicaid, and Children Health Insurance Programs.
|
||||
1.6 CMS The federal agency, Center for Medicare and Medicaid Services, responsible for
|
||||
administering the Medicare, Medicaid and Children Health Insurance Programs.
|
||||
|
||||
|
||||
Start of Page No. = 2
|
||||
|
||||
1.7
|
||||
Clean Claim. An electronic claim or paper claim for payment for services that meets the Texas
|
||||
and/or federal statutory and regulatory requirements for "clean claim."
|
||||
1,8
|
||||
1.8
|
||||
Community Protocols. The rules, procedures, policies, protocols, and other conditions to be followed
|
||||
by Participating Physicians, Providers and Members with respect to providing Covered Services under a particular
|
||||
Benefit Plan/Program, generally defined in Community's Provider Manual.
|
||||
Benefit Plan/Program generally defined in Community's Provider Manual
|
||||
1.9
|
||||
Coinsurance. A component of Member Expense, generally reflected as a percentage, in an
|
||||
amount identified in Member's Benefit Plan/Program, paid to a Provider or a Physician for Covered Services by
|
||||
Coinsurance A component of Member Expense, generally reflected as a percentage, in an
|
||||
amount identified in Member's Benefit Plan/Program paid to a Provider or a Physician for Covered Services by
|
||||
Member.
|
||||
1.10 Copayment. A component of Member Expense, generally reflected as a flat or fixed dollar amount
|
||||
either per Covered Service or per encounter, identified in Member's Benefit Plan/Program, and collected by
|
||||
Provider or Physician at the time Member receives Covered Services.
|
||||
1.10 Copayment A component of Member Expense, generally reflected as a flat or fixed dollar amount
|
||||
either per Covered Service or per encounter, identified in Member's Benefit Plan/Program and collected by
|
||||
Provider or Physician at the time Member receives Covered Services
|
||||
1.11 Coordination of Benefits. The allocation of financial responsibility between two or more Payors of
|
||||
health care services, each with a legal duty to pay for or provide Covered Services to a Member at the same time.
|
||||
1.12
|
||||
Covered Services. The Medically Necessary health care services, products, or supplies for which a
|
||||
1.12 Covered Services. The Medically Necessary health care services, products or supplies for which a
|
||||
Member is entitled to receive coverage from Community or other Payor, pursuant to the terms of the Member's
|
||||
Benefit Plan/Program.
|
||||
1.13 Deductible. A component of Member Expense, generally reflected as fixed dollar amount during
|
||||
a specific benefit period, typically one year, identified in Member's Benefit Plan/Program; payable by a Member
|
||||
prior to Community's or Payor's obligation to make payment for Covered Services. Deductibles may apply to a
|
||||
Member or to a Member's eligible dependents.
|
||||
1.14
|
||||
Emergency Behavioral-Health Condition. Any condition, without regard to the nature or cause of the
|
||||
Benefit Plan/Program
|
||||
1.13 Deductible A component of Member Expense, generally reflected as fixed dollar amount during
|
||||
a
|
||||
specific benefit period, typically one year, identified in Member's Benefit Plan/Program; payable by a Member
|
||||
prior to Community's or Payor's obligation to make payment for Covered Services Deductibles may apply to a
|
||||
Member or to a Member's eligible dependents
|
||||
1.14 Emergency Behavioral-Health Condition. Any condition, without regard to the nature or cause of the
|
||||
condition, which requires immediate intervention and/or medical attention without which an individual would present
|
||||
an immediate danger to himself/herself or others or which renders the individual incapable of controlling. knowing
|
||||
or understanding the consequences of his/her actions.
|
||||
@@ -143,7 +102,9 @@ licensed and/or authorized under the laws of the State, who are employed by or c
|
||||
to provide Covered Services under the terms of this Agreement.
|
||||
Page 2 of 38
|
||||
|
||||
|
||||
Start of Page No. = 3
|
||||
|
||||
1.20 Medically Necessary/Medical Necessity. Those Covered Services that Community determines
|
||||
under the applicable Utilization Management Program to be: (i) appropriate and necessary for the symptoms,
|
||||
diagnosis, or treatment of a medical condition; (ii) provided for the diagnosis or direct care and treatment of a medical
|
||||
@@ -198,7 +159,9 @@ provide a health care service in this State, including, but not limited to: (i)
|
||||
pharmacist, optometrist, registered optician, or acupuncturist; or (ii) a pharmacy, hospital, or other institution or
|
||||
Page 3 of 38
|
||||
|
||||
|
||||
Start of Page No. = 4
|
||||
|
||||
organization; a person who is wholly owned or controlled by a provider or by a group of providers who are
|
||||
licensed or otherwise authorized to provide the same health care service; or a person who is wholly owned or
|
||||
controlled by one or more hospitals and physicians, including a physician-hospital organization.
|
||||
@@ -251,7 +214,9 @@ identification number, the first date on which the Member became enrolled or the
|
||||
Provider can use to obtain the date, and the Member's Primary Care Physician or Primary Care Provider.
|
||||
Page 4 of 38
|
||||
|
||||
|
||||
Start of Page No. = 5
|
||||
|
||||
2.5
|
||||
Regulatory Compliance. Community agrees that it shall comply with all applicable requirements of
|
||||
State and federal authorities, all municipal ordinances and regulations, and all State and federal statutes and
|
||||
@@ -307,7 +272,9 @@ is responsible for the compliance of its Healthcare Professionals of all the ter
|
||||
References to "Contracted Provider" also include Healthcare Professionals.
|
||||
Page 5 of 38
|
||||
|
||||
|
||||
Start of Page No. = 6
|
||||
|
||||
3.3
|
||||
Contracted Provider Representations and Warranties. Contracted Provider represents and warrants
|
||||
that Contracted Provider and Healthcare Professionals, now and for the duration of this Agreement shall remain: (i)
|
||||
@@ -367,7 +334,9 @@ Authorization or Referral in advance of providing Covered Services, except for E
|
||||
Provider acknowledges that failure to obtain required Prior Authorization or Referral will impact Contracted Provider's
|
||||
Page 6 of 38
|
||||
|
||||
|
||||
Start of Page No. = 7
|
||||
|
||||
compensation for said Covered Services. For a situation involving Emergency Services, Contracted Provider agrees
|
||||
to ensure that Community or Payor is notified as soon as possible, but no later than twenty-four (24) hours after the
|
||||
provision of Covered Services or the ordering of the other Covered Services, or on the next business day.
|
||||
@@ -425,7 +394,9 @@ operational hardship; or any other special circumstance that would justify a wai
|
||||
discretion will determine whether to agree to waive the requirement.
|
||||
Page 7 of 38
|
||||
|
||||
|
||||
Start of Page No. = 8
|
||||
|
||||
3.18
|
||||
Credentialing of Contracted Provider and/or Healthcare Professional, Contracted Provider shall
|
||||
submit to Community a credentials application, as modified from time to time by Community, TDI or other regulatory
|
||||
@@ -480,7 +451,9 @@ authorized agents, and appropriate representatives of any State and/or Federal r
|
||||
business hours for review, inspection, and/or audit.
|
||||
Page 8 of 38
|
||||
|
||||
|
||||
Start of Page No. = 9
|
||||
|
||||
4.2
|
||||
Medical Records. Contracted Provider shall maintain a complete medical record for each Member
|
||||
for which Contracted Provider or Healthcare Professional renders Covered Services hereunder. Such medical
|
||||
@@ -538,7 +511,9 @@ Payor shall: (i) pay the total amount of the claim in accordance with Exhibit B;
|
||||
writing why the claim will not be paid; or (iii) pay the portion of the claim that is not in dispute and notify Contracted
|
||||
Page 9 of 38
|
||||
|
||||
|
||||
Start of Page No. = 10
|
||||
|
||||
Provider in writing why the remaining portion of the claim was not paid. When medical information is requested to
|
||||
support payment, Contracted Provider shall have twenty-one (21) calendar days to provide information to Payor.
|
||||
Not later than fifteen (15) days following receipt of Contracted Provider's response to Payor's request for additional
|
||||
@@ -597,7 +572,9 @@ Payor, Contracted Provider's sole recourse shall be against Payor through the ba
|
||||
Payor.
|
||||
Page 10 of 38
|
||||
|
||||
|
||||
Start of Page No. = 11
|
||||
|
||||
5.7
|
||||
Benefit Plan/Program Participation and Compensation Rates. The parties agree that Exhibit B shall
|
||||
outline: (1) the Benefit Plan(s)/Program(s) in which Provider participates; and (2) the applicable compensation to
|
||||
@@ -656,7 +633,9 @@ the each other Payor with which the same claim is being filed. Payor will coordi
|
||||
in accordance with the terms of the Member's Benefit Plan/Program and applicable State and federal laws, rules,
|
||||
Page 11 of 38
|
||||
|
||||
|
||||
Start of Page No. = 12
|
||||
|
||||
and regulations. If a Member has coverage from more than one payment source, Payor will coordinate benefits with
|
||||
such other payment source in accordance with the Member's Benefit Plan/Program. Contracted Provider agrees to
|
||||
share information obtained or documentation required by Payor to facilitate Payor's coordinate of such other
|
||||
@@ -711,7 +690,9 @@ review data and other information as may be required or requested under a Qualit
|
||||
comply with all confidentiality requirements regarding a Quality Improvement Program. In the event that the
|
||||
Page 12 of 38
|
||||
|
||||
|
||||
Start of Page No. = 13
|
||||
|
||||
standard or quality of care furnished by a Contracted Provider is found to be unacceptable under any Quality
|
||||
Improvement Program, Community shall give written notice to Contracted Provider and/or Healthcare Professional
|
||||
to correct the specified deficiencies within the time period specified in the notice, Such Contracted Provider shall
|
||||
@@ -769,7 +750,9 @@ Contracted Provider shall further indemnify, defend, and hold harmless Community
|
||||
Payor, and their representatives, officers, directors, employees, and agents individually and/or collectively from any
|
||||
Page 13 of 38
|
||||
|
||||
|
||||
Start of Page No. = 14
|
||||
|
||||
and all causes of action, liabilities, claims, or other expenses (including, without limitation, costs of suit, attorney's
|
||||
fees, and/or mediation expenses) that might be asserted against Community and its representatives, officers,
|
||||
directors, employees, and agents individually arising from, or pertaining to, the failure or refusal of Contracted
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+143
-167
@@ -1,55 +1,36 @@
|
||||
Document Index
|
||||
14001190 1
|
||||
to the 2PROVIDER SERVICES AGREEMENT 2between 2ALL HEALTH, INC. AFFILIATES 2and 2
|
||||
AMENDMENT 2
|
||||
THE REGENTS OF THE SCHOOL 2OF CALIFORNIA UCDD HEALTHCARE NETWORK 2
|
||||
ADDENDUM E 6
|
||||
FEE-FOR-SERVICE COMPENSATION SCHEDULE 6
|
||||
Assistant Surgeons: 6
|
||||
For Obstetrical Care: 6
|
||||
For Anesthesiology Services: 6
|
||||
|
||||
|
||||
|
||||
Start of Page No. = 1
|
||||
|
||||
14001190
|
||||
Pages: 5
|
||||
1) TODAY'S DATE: 2010-01-29
|
||||
2) DOCUMENT TYPE
|
||||
XCONTRACT
|
||||
CORRESPONDENCE
|
||||
TERM SHEET
|
||||
XCONTRACT OCORRESPONDENCE TERM SHEET
|
||||
3) PROVIDER TYPE
|
||||
HOSP
|
||||
PPG
|
||||
ANCILLARY
|
||||
HOSP XPPG CANCILLARY
|
||||
POP
|
||||
CLINIC
|
||||
FQHC
|
||||
4) PROVIDER SYSTEM:
|
||||
5) PROVIDER NAME: UDCC Medical Group
|
||||
6)
|
||||
FOR AGREEMENTS INCLUDING ALL FORMS OF CONTRACTS:
|
||||
6) FOR AGREEMENTS INCLUDING ALL FORMS OF CONTRACTS:
|
||||
AGREEMENT - DOCUMENT TYPE
|
||||
PPA
|
||||
AGR
|
||||
(AMD
|
||||
AGR XAMD
|
||||
LOA
|
||||
AAD
|
||||
UAAD
|
||||
SET
|
||||
CDM
|
||||
EFFECTIVE DATE: 2005-01-01
|
||||
- 7) FOR SUPPORTING DOCUMENTS (ALL NON CONTRACTS):
|
||||
7) FOR SUPPORTING DOCUMENTS (ALL NON CONTRACTS):
|
||||
DOCUMENT TYPE
|
||||
TS
|
||||
ITS
|
||||
REI
|
||||
SRS
|
||||
COR
|
||||
FND
|
||||
OTHER:
|
||||
YEAR RANGE:
|
||||
8) TAX ID NUMBER:
|
||||
12-3456789
|
||||
8) TAX ID NUMBER: 12-3456789
|
||||
POST SCANNING
|
||||
Scanned Electronic Document Verified
|
||||
(initial please)
|
||||
@@ -60,106 +41,115 @@ Original Files removed and placed in Original Files Room
|
||||
Conversion to Digital Files Completed
|
||||
(initial please)
|
||||
|
||||
|
||||
Start of Page No. = 2
|
||||
|
||||
AMENDMENT
|
||||
to the
|
||||
PROVIDER SERVICES AGREEMENT
|
||||
between
|
||||
ALL HEALTH, INC. AFFILIATES
|
||||
ALL HEALTH INC. AFFILIATES
|
||||
and
|
||||
THE REGENTS OF THE SCHOOL
|
||||
OF CALIFORNIA UCDD HEALTHCARE NETWORK
|
||||
The Provider Services Agreement ("Agreement") effective January 1, 2000, between The Regents of the School
|
||||
of California, a Constitutional Corporation; on behalf of the UCDD Medical Group a Participating Physician Council
|
||||
("PPC"), and All Health, Inc. Affiliates ("AHI"), as subsequently amended, is hereby further amended effective
|
||||
The Provider Services Agreement ("Agreement") effective January 1. 2000. between The Regents of the School
|
||||
of California a Constitutional Corporation: on behalf of the UCDD Medical Group a Participating Physician Council
|
||||
("PPC"),
|
||||
and All Health, Inc. Affiliates ("AHI"), as subsequently amended, is hereby further amended effective
|
||||
January 1, 2005.
|
||||
AHI and PPC hereby agree to amend the Agreement as follows:
|
||||
IAHI and PPC hereby agree to amend the Agreement as follows:
|
||||
1.
|
||||
Section 4.3 Billing and Payment subsections (a), (c), and (d) only are hereby deleted and replaced as follows:
|
||||
(a)
|
||||
Billing. Provider shall submit to AHI or Payor via AHI's electronic claims submission
|
||||
Billing Provider shall submit to AHI or Payor via AHI's electronic claims submission
|
||||
program or by hard copy, clean, complete and accurate claims for Contracted Services in accordance
|
||||
with the Operations Manual and the applicable Benefit Program. Provider shall submit claims within
|
||||
ninety (90) days of rendering Contracted Services. Where AHI is the secondary payor under
|
||||
with the Operations Manual and the applicable Benefit Program Provider shall submit claims within
|
||||
ninety (90) days of rendering Contracted Services Where AHI is the secondary payor under
|
||||
Coordination of Benefits, such ninety (90) day period shall commence immediately after the primary
|
||||
payor has paid or denied the claim. If AHI does not receive the requested information from
|
||||
payor has paid or denied the claim. If |AHI does not receive the requested information from
|
||||
Provider within said ninety (90) days, claim (s) shall be denied without recourse to resubmit and
|
||||
AHI shall have no liability for such claim.
|
||||
AHI shall not be under any obligation to pay Provider for any claim not timely submitted as set
|
||||
forth above. Provider shall not seek payment from any Member in the event AHI does not pay
|
||||
Provider for a claim not timely submitted.
|
||||
AHI shall have no liability for such claim
|
||||
IAHI shall not be under any obligation to pay Provider for any claim not timely submitted as set
|
||||
forth above Provider shall not seek payment from any Member in the event AHI does not pay
|
||||
Provider for a claim not timely submitted
|
||||
(c)
|
||||
Adjustments and Appeals Provider. shall submit requests for adjustments and/or
|
||||
Adjustments and Appeals Provider shall submit requests for adjustments and/or
|
||||
appeals regarding claim payments to AHI within three hundred sixty-five days (365) calendar days
|
||||
after the date of the payment of such claim to Provider. In the event Provider fails to appeal a
|
||||
claim within such time period, Provider shall not have the right to appeal such claim.
|
||||
claim within such time period. Provider shall not have the right to appeal such claim
|
||||
(d)
|
||||
Offsetting AHI shall have the right to offset any amounts owed to AHI by PPG,
|
||||
including but not limited to, amounts owed by PPG under loans guaranteed by AHI, errors, or AHI
|
||||
interim payment for Contracted Services, including Capitation payments. Notwithstanding any
|
||||
Offsetting AHI shall have the right to offset any amounts owed to AHI by PPG.
|
||||
including but not limited to. amounts owed by PPG under loans guaranteed by AHI, errors, or AHI
|
||||
interim payment for Contracted Services, including Capitation payments Notwithstanding any
|
||||
other provision of this Agreement or any other contract to the contrary, only deficits in the shared
|
||||
risk programs which provide financial incentives for the control or management of Shared Risk
|
||||
Services' expenses or utilization will neither be collected from PPG by AHI nor offset against
|
||||
PPG Capitation; provided however, that AHI shall not be restricted from (i) offsetting such
|
||||
deficits against payments to PPG including, but not limited to, surpluses from other shared risk
|
||||
PPG Capitation: provided however, that AHI shall not be restricted from (i) offsetting such
|
||||
deficits against payments to PPG including but not limited to, surpluses from other shared risk
|
||||
programs, stop loss payments, bonus or other incentive program payments; (ii) establishing
|
||||
reasonable withholds from Capitation approved by DMHC as set forth in the applicable
|
||||
Addendum to offset PPG liability when the cost of Shared Risk Services exceed the Shared Risk
|
||||
Budget (Withhold Fund); or (iii) carrying forward such shared risk program deficits to be applied
|
||||
against future year's program surpluses and Withhold Fund. Each PPG numbered site. shall be
|
||||
calculated as a separate entity and any payments to or from PPG with multiple sites shall be net
|
||||
amount due/owed from all sites. In no event shall PPG be required to make any cash payment to
|
||||
AHI for any deficit in a shared risk program for institutional services.
|
||||
To the extent AHI identifies financial liabilities, including overpayments, owed to AHI by PPG
|
||||
under this Agreement, the intent to collect such financial liabilities shall be communicated to PPG.
|
||||
Budget (Withhold Fund): or (iii) carrying forward such shared risk program deficits to be applied
|
||||
against future year's program surpluses and Withhold Fund Each PPG numbered site shall be
|
||||
calculatEd as a separate entity and any payments to or from PPG with multiple sites shall be net
|
||||
amount duelowed from all sites. In no event shall PPG be required to make any cash payment to
|
||||
AHI for any deficit in a shared risk program for institutional services
|
||||
To the extent AHI identifies financial liabilities including overpayments owed to AHI by PPG
|
||||
under this Agreement, the intent to collect such financial liabilities shall be communicated to PPG
|
||||
Proof of such liabilities and the methodology used to make such determination shall be subject to
|
||||
UCDD 2005 Amd.d
|
||||
Effective January 1, 2005
|
||||
UCDD 2005 Amd doc
|
||||
Effective January 1. 2005
|
||||
|
||||
|
||||
Start of Page No. = 3
|
||||
external actuarial review, with PPG bearing the cost of such review. No collection of such
|
||||
liabilities shall occur until PPG has a reasonable opportunity to conduct such review, provided that
|
||||
|
||||
external actuarial review. with PPG bearing the cost of such review. No collection of such
|
||||
liabilities shall occur until PPG has a reasonable opportunity to conduct such review. provided that
|
||||
such review occurs within ten (10) business days of communication to PPG by AHI
|
||||
Concurrently, to the extent that PPG identifies financial liabilities owed to PPG by AH|
|
||||
under
|
||||
this
|
||||
Agreement, the intent to collect such financial liabilities shall be communicated to AHI. Proof of
|
||||
Concurrently, to the extent that PPG identifies financial liabilities owed to PPG by AHI under this
|
||||
Agreement the intent to collect such financial liabilities shall be communicated to AHI. Proof of
|
||||
such liability, and the methodology used to make such determination shall be subject to external
|
||||
actuarial review, with AHI bearing the cost of such review. No collection of such liability shall
|
||||
occur until AHI has a reasonable opportunity to conduct such review, provided that such review
|
||||
occurs within ten (10) days of communication to AHI by PP.G.
|
||||
actuarial review, with AHI bearing the cost of such review No collection of such liability shall
|
||||
occur until AHI has a reasonable opportunity to conduct such review. provided that such review
|
||||
occurs within ten (10) days of communication to AHI by PPG
|
||||
2.
|
||||
Addendum B, Section B.1.1, Capitation Rates, is hereby deleted in its entirety and replaced with the
|
||||
Addendum B, Section B.I.I. Capitation Rates, is hereby deleted in its entirety and replaced with the
|
||||
following:
|
||||
1.1
|
||||
Capitation Rates. PPG Capitation for Standard HMO Members shall be determined on a
|
||||
Capitation Rates, PPG Capitation for Standard HMO Members shall be determined on a
|
||||
monthly basis by multiplying the following normalized PMPM rates by the age, sex and benefit
|
||||
plan factors set forth in Addendum B for each assigned Member. Normalized rates represent the
|
||||
plan factors set forth in Addendum B for each assigned Member Normalized rates represent the
|
||||
PMPM prior to the adjustment for PPG's assigned Members' age, sex and benefit plan. Actual
|
||||
PPG gross Capitation shall fluctuate from month to month to the extent that PPG's age, sex and
|
||||
benefit plan mix fluctuates.
|
||||
benefit plan mix fluctuates
|
||||
-------Table Start--------
|
||||
[["Effective Period","Standard HMO"],["January 1. 2005","$75.15 PMPM"]]
|
||||
-------Table End--------
|
||||
3.
|
||||
Addendum B, Section C.1.1, Capitation Rates, is hereby deleted in its entirety and replaced with the
|
||||
Addendum B. Section C.1.1. Capitation Rates, is hereby deleted in its entirety and replaced with the
|
||||
following:
|
||||
1.1
|
||||
Capitation Rates. PPG Capitation for Small Group HMO Members shall be determined
|
||||
on a monthly basis by multiplying the following normalized PMPM. rates by the age, sex and
|
||||
benefit plan factors set forth in Addendum B for each assigned Member. Normalized PMPM rates
|
||||
Capitation Rates, PPG Capitation for Small Group HMO Members shall be determined
|
||||
on a monthly basis by multiplying the following normalized PMPM rates by the age, sex and
|
||||
benefit plan factors set forth in Addendum B for each assigned Member Normalized PMPM rates
|
||||
represent the PMPM prior to the adjustment for PPG's assigned Members' age, sex and benefit
|
||||
plan. Actual PPG gross Capitation shall fluctuate from month to month to the extent that PPG's
|
||||
age, sex and benefit plan mix fluctuates.
|
||||
age, sex and benefit plan mix fluctuates
|
||||
-------Table Start--------
|
||||
[["Effective Period","Small Group HMO"],["January 1, 2005","$67.59 PMPM"]]
|
||||
-------Table End--------
|
||||
4.
|
||||
Addendum C, Section B.2.1, Compensation for PPG Capitated Services, is deleted and replaced with the
|
||||
Addendum C. Section B.2.1, Compensation for PPG Capitated Services is deleted and replaced with the
|
||||
following:
|
||||
2.1
|
||||
Compensation for PPG Capitated Services. As compensation for rendering PPG
|
||||
Capitated Services as defined herein, HMO shall pay PPG Capitation at forty. one and fifty eight
|
||||
Capitated Services as defined herein, HMO shall pay PPG Capitation at forty one and fifty eight
|
||||
hundreds percent (41.58%) of Monthly Revenue as set forth below for each Medicare HMO Member
|
||||
eligible to receive such services from PPG during any particular month.
|
||||
eligible to receive such services from PPG during any particular month
|
||||
Capitation shall be computed on the basis of the most current information available and shall be
|
||||
paid by HMO by wire transfer on or before the fifteenth (15th) day of each month or the first
|
||||
business day following the fifteenth if the fifteenth is a holiday or on a weekend or within two (2)
|
||||
days of CMS's payment to HMO; whichever is later. Each Capitation payment shall be
|
||||
days of CMS's payment to HMO: whichever is later. Each Capitation payment shall be
|
||||
accompanied by a remittance summary. The remittance summary identifies the total Capitation
|
||||
payable and those Medicare HMO Members for whom Capitation is being paid. In the event of a
|
||||
Capitation error, resulting in an overpayment or underpayment to PPG, HMO shall adjust
|
||||
@@ -168,146 +158,132 @@ UCDD Amendment 1/1/05
|
||||
2
|
||||
|
||||
|
||||
-------Table Start--------
|
||||
|
||||
[['Effective Period', 'Standard HMO'], ['January 1, 2005', '$75.15 PMPM']]
|
||||
None
|
||||
-------Table End--------
|
||||
-------Table Start--------
|
||||
|
||||
[['Effective Period', 'Small Group HMO'], ['January 1, 2005', '$67.59 PMPM']]
|
||||
None
|
||||
-------Table End--------
|
||||
|
||||
Start of Page No. = 4
|
||||
|
||||
Per PPG's request and upon receipt of reconciliation report from PPG, AHI agrees to reevaluate
|
||||
the withhold amount of $1.57 PMPM for the mental health and substance abuse services as set
|
||||
forth in section 6 of this Amendment for the period of January 1, 2005-December 31,2005. Based
|
||||
forth in section 6 of this Amendment for the period of January 1. 2005-December 31,2005. Based
|
||||
upon audit result AHI will adjust the capitation accordingly to ensure that the equivalent withhold
|
||||
against Monthly Revenue does not exceed $1.57 PMPM for this period only.
|
||||
AHI agrees to offer PPG's participating providers for Mental Health and substance abuse services
|
||||
and will make best effort to direct Medicare HMO members to these providers.
|
||||
5.
|
||||
Addendum C, Section B.3.1, Shared Risk Budget, is deleted in its entirety and is replaced with the
|
||||
following:
|
||||
Addendum C. Section B.3.1. Shared Risk Budget is deleted in its entirety and is replaced with the
|
||||
following>
|
||||
3.1
|
||||
Shared Risk Budget. At the final settlement, upon the event of a deficit, as a
|
||||
contingency for any PPG liability, HMO shall deduct two percent %) of PPG's Capitation and
|
||||
place such amount in the Withhold Fund as described in this Agreement. Each month, HMO shall
|
||||
Shared Risk Budget. At the final settlement upon the event of a deficit, as a
|
||||
contingency for any PPG liability. HMO shall deduct two percent (2 %) of PPG's Capitation and
|
||||
place such amount in the Withhold Fund as described in this Agreement Each month, HMO shall
|
||||
fund the Shared Risk Budget for each eligible Medicare HMO Member at forty-three and forty
|
||||
three hundredths percent (43.43%) of Monthly Revenue.
|
||||
6.
|
||||
Addendum C.2, DIVISION OF FINANCIAL RESPONSIBILITY MATRIX OF HMO AND PPG
|
||||
CAPITATED SERVICES MEDICARE BENEFIT PROGRAM, of the Agreement shall be amended only for the
|
||||
three hundredths percent (43.43%) of Monthly Revenue
|
||||
6
|
||||
Addendum C.2. DIVISION OF FINANCIAL RESPONSIBILITY MATRIX OF HMO AND PPG
|
||||
CAPITATED SERVICES MEDICARE BENEFIT PROGRAM of the Agreement shall be amended only for the
|
||||
following Service categories as indicated below:
|
||||
-------Table Start--------
|
||||
[["","PPG CAPITATED SERVICES","HMO RISK SERVICES","SHARED RISK/HOSPITAL CAPITATED SERVICES"],["CHEMICAL DEPENDENCE","","",""],["(Rehabilitation Services)","","",""],["Inpatient Facility Component","","X",""],["Inpatient Professional Component","","",""],["- Outpatient Facility Component","","",""],["- Outpatient Professional Component","","X",""],["Inpatient Detox Facility Component","","","X"],["Inpatient Detox Professional Component","","",""],["MENTAL HEALTH - Inpatient","","",""],["Facility Component","","X",""],["Professional Component","","X",""],["MENTAL HEALTH - Outpatient","","",""],["Facility Component","","",""],["Professional Component","","X",""]]
|
||||
-------Table End--------
|
||||
7.
|
||||
Addendum E is deleted in its entirety and is replaced with a new Addendum E attached.
|
||||
Addendum E is deleted in its entirety and is replaced with a new Addendum E attached
|
||||
8.
|
||||
Addendum F.1 Fee-For-Service Compensation Schedule is amended by adding the following:
|
||||
Injectables: As to injectables for which HMO is responsible for reimbursement, HMO shall
|
||||
Injectables As to injectables for which HMO is responsible for reimbursement, HMO shall
|
||||
compensate PPG at one hundred ten percent (110%) of the State of California Medi-Cal Fee
|
||||
Schedule rates in effect at the time of service. If such medication is not listed on the Medi-Cal Fee
|
||||
Schedule rates in effect at the time of service If such medication is not listed on the Medi-Cal Fee
|
||||
Schedule, the value will be determined by the Average Wholesale Price (AWP) as calculated by
|
||||
HNI in accordance with the Medi-Cal methodology
|
||||
Such rates shall be payment-in-full, except for applicable copayments. HMO shall reimburse PPG
|
||||
at such rates, less applicable copayment. HMO shall not be responsible for reimbursing the
|
||||
Member Physicians for such injectables. PPG shall seek reimbursement from HMO for such
|
||||
Such rates shall be payment-in-full, except for applicable copayments HMO shall reimburse PPG
|
||||
at such rates, less applicable copayment HMO shall not be responsible for reimbursing the
|
||||
Member Physicians for such injectables PPG shall seek reimbursement from HMO for such
|
||||
injectables and shall submit claims for such services to HMO using the CMS 1500 Form and the
|
||||
appropriate CPT-4, HCPCS and NDC codes.
|
||||
appropriate CPT-4, HCPCS and NDC codes
|
||||
UCDD Amendment 1/1/05
|
||||
-3--
|
||||
|
||||
|
||||
-------Table Start--------
|
||||
c11f6b8d-47e5-4a67-9d2b-6fe6f18fd08e
|
||||
[[None, 'PPG CAPITATED SERVICES', 'HMO RISK SERVICES', 'SHARED RISK/HOSPITAL CAPITATED SERVICES'], ['CHEMICAL DEPENDENCE', None, None, None], ['(Rehabilitation Services)', None, None, None], ['- Inpatient Facility Component', None, 'X', None], ['- Inpatient Professional Component', '[ ]', 'X', None], ['- Outpatient Facility Component', None, None, None], ['- Outpatient Professional Component', None, None, None], ['- Inpatient Detox Facility Component', None, None, 'X'], ['- Inpatient Detox Professional Component', None, None, None], ['MENTAL HEALTH-Inpatient -', None, None, None], ['- Facility Component', '[ ]', '[X]', '[ ]'], ['- Professional Component', None, None, None], ['MENTAL HEALTH - Outpatient', None, None, None], ['Facility Component', '[ ]', 'X [X]', '[ ]'], ['- Professional Component', None, None, None]]
|
||||
6. Addendum C.2, DIVISION OF FINANCIAL RESPONSIBILITY MATRIX OF HMO AND PPG CAPITATED SERVICES MEDICARE BENEFIT PROGRAM, of the Agreement shall be amended only for the following Service categories as indicated below: 7. Addendum E is deleted in its entirety and is replaced with a new Addendum E attached.
|
||||
-------Table End--------
|
||||
|
||||
Start of Page No. = 5
|
||||
|
||||
9.
|
||||
AHI I shall pay PPG eighty-five thousand dollars ($85,000) as a lump sum payment for PPG to use to fund a
|
||||
AHI I shall pay PPG eighty-five thousand dollars ($85,000) as a lump sum payment for PPG to use to fund
|
||||
a
|
||||
twenty four month e-visit program with Relay Health ("E-Visit Program"). PPG shall use such monies to implement
|
||||
the E-Visit Program for Commercial Members from January 1; 2005 through December 31 2006. PPG shall provide
|
||||
information regarding the usage and benefits of the E-Visit Program to AHI upon request. In the event that PPG and
|
||||
Relay Health do not execute an agreement by July 1, 2005, PPG shall pay AHI eighty-five thousand dollars,
|
||||
($85,000) within thirty (30) days of such date.
|
||||
Relay Health do not execute am agreement by July 1, 2005, PPG shall pay AHI eighty-five thousand dollars,
|
||||
($85,000) within thirty (30) days of such date
|
||||
In consideration for all of the payment terms set forth herein, including but not limited to the increase in the
|
||||
Commercial rates, PPG understands and agrees that HNI shall be the exclusive Medicare Advantage payor
|
||||
contracted with Provider, for any and all Medicare Advantage products including, but not limited to, HMO products,
|
||||
PPO products or demonstration projects, from January 1, 2005 through December 31, 2006.
|
||||
Commercial rates, PPG understands and agrees that HNI shall he the exclusive Medicare Advantage payor
|
||||
contracted with Provider, for any and all Medicare Advantage products including, but not limited to. HMO products.
|
||||
PPO products or demonstration projects, from January 1, 2005 through December 31. 2006.
|
||||
10.
|
||||
Except as otherwise provided in this Amendment, all other terms and conditions of the Agreement remain
|
||||
unchanged and in full force and effect.
|
||||
Except as otherwise provided in this Amendment all other terms and conditions of the Agreement remain
|
||||
unchanged and is full force and effect.
|
||||
IN WITNESS WHEREOF, the parties hereto have executed this Amendment on the dates indicated below.
|
||||
UDCC Medical Group
|
||||
All Health, Inc. Affiliates
|
||||
Hemith
|
||||
Signature
|
||||
Street
|
||||
Signature
|
||||
Tom Pete
|
||||
Kinjal Dave
|
||||
CFO, UDCC Health Sciences
|
||||
Network Management & Development Officer
|
||||
CFO. UDCC Health Sciences
|
||||
1/20/05
|
||||
Date
|
||||
All Health, Inc. Affiliates
|
||||
Peanth
|
||||
Signature
|
||||
Kinjal Dave
|
||||
Network Management & Development Officer
|
||||
2-2-05
|
||||
Date
|
||||
Date
|
||||
Provider Tax Identification Number: 12-3456789
|
||||
Provider Tax Identification Number 12-3456789
|
||||
UDCC Amendment 1/1/05
|
||||
-4-
|
||||
|
||||
This page has 2 signature.
|
||||
|
||||
|
||||
Start of Page No. = 6
|
||||
|
||||
ADDENDUM E
|
||||
FEE-FOR-SERVICE COMPENSATION SCHEDULE
|
||||
FEE-FOR-FER-SERVICE COMPENSATION SCHEDULE
|
||||
PPG or Member Physician shall be compensated for non-capitated Contracted Services, less applicable Copayments, in
|
||||
an amount equal to the lesser of: (a) one hundred ten percent (110%) of the Medicare allowable charges based on the
|
||||
an amount equal to the lesser of (a) one hundred ten percent (110%) of the Medicare allowable charges based on the
|
||||
Medicare Resource Based Relative Value Scale (RBRVS) unit values and CMS Geographical Practice Cost Indices as
|
||||
published in the most current published edition of the Federal Register; or (b) seventy-five percent (75%) of PPG's
|
||||
allowable billed charges.
|
||||
For "by report".-procedures, procedures not listed, or procedures with relativities not established in RBRVS, PPG shall
|
||||
be compensated at sixty percent (60%) of PPG or the Participating Provider's billed charges, less any applicable
|
||||
Copayment.
|
||||
Injectables and HMO Designated Vendor. As to injectables, for which HMO is responsible for reimbursement,
|
||||
PPG shall obtain such injectables from the HMO designated vendors as described in the Operations Manual. If such
|
||||
published in the most current published edition of the Federal Register: or (b) seventy-five percent (75%) of PPG's
|
||||
allowable billed charges
|
||||
For "by report".procedures procedures not listed. or procedures with relativities not established in RBRVS, PPG shall
|
||||
be compensated at sixty percent (60%) of PPG or the Participating Provider's billed charges. less any applicable
|
||||
Copayment
|
||||
Injectables and HMO Designated Vendor As to injectables for which HMO is responsible for reimbursement
|
||||
PPG shall obtain such injectables from the HMO designated vendors as described in the Operations Manual If such
|
||||
injectables are not available from the HMO designated vendor, PPG shall be compensated at the lesser of: a) the
|
||||
PPG's billed charges; b) the CMS Single Drug Pricer c) the Average Wholesale Price (AWP) as established by First
|
||||
Databank, Medispan, MDX and as reflected in HMO's database which is updated semi-annually, less ten percent
|
||||
(10%); or d) the lowest acquisition cost provided through services made available by HMO. AWP reimbursement is
|
||||
based on the lowest AWP for the specific antigen. Multi-dose vials shall be reimbursed on a per dose basis.
|
||||
Assistant Surgeons:
|
||||
PPG's billed charges b) the CMS Single Drug Pricer c) the Average Wholesale Price (AWP) as established by First
|
||||
Databank, Medispan. MDX and as reflected in HMO's database which is updated semi-annually, less ten percent
|
||||
(10%); or d) the lowest acquisition cost provided through services made available by HMO AWP reimbursement is
|
||||
based on the lowest AWP for the specific antigen. Multi-dose vials shall be reimbursed on a per dose basis
|
||||
Assistant Surgeons
|
||||
PPG or Participating Provider shall be compensated for Contracted Services at twenty percent (20%) of the surgeon's
|
||||
reimbursement as determined above.
|
||||
reimbursement as determined above
|
||||
For Obstetrical Care:
|
||||
Compensation for obstetrical services shall be at the lesser of the PPG's billed charges, or:
|
||||
Compensation for obstetrical services shall be at the lesser of the PPG's billed charges, or
|
||||
-------Table Start--------
|
||||
[["CPT 59400-Global Obstetric care with vaginal delivery","$1700.00"],["CPT 59510 Global Obstetric care with Cesarean delivery","$1700.00"]]
|
||||
-------Table End--------
|
||||
For Anesthesiology Services:
|
||||
PPG shall be compensated for anesthesiology services which are Covered Services at the lesser of (a) $34. 00 per unit
|
||||
value in accordance with the American Society of Anesthesiology (ASA) unit scale, or (b) 75% of the PPG's usual
|
||||
billed charges.
|
||||
billed charges
|
||||
OB Epidural shall be compensated under the unit value conversion factor stated above for Anesthesiology and applied
|
||||
to the ASA Base Units and Time Units as set forth below:
|
||||
BASE UNITS:
|
||||
TIME UNITS:
|
||||
CONFIDENTIAL, PROPRIETARY AND TRADE SECRET
|
||||
-------Table Start--------
|
||||
[["00955 - Continuous epidural, labor and vaginal delivery","5 units"],["00857 - Continuous epidural, labor and C-Section","7 units"],["00850 - Planned C-Section","7 units"]]
|
||||
-------Table End--------
|
||||
TIME UNITS
|
||||
Start up time:
|
||||
up to three units for first hour of labor time plus
|
||||
Labor time:
|
||||
two units for each additional hour of labor, plus
|
||||
Surgery time:
|
||||
one unit for each fifteen minute interval of surgical time if labor goes
|
||||
into C-Section or of planned C-Section
|
||||
CONFIDENTIAL PROPRIETARY AND TRADE SECRET
|
||||
UCDD Amendment 1/1/05
|
||||
-5-
|
||||
.5.
|
||||
|
||||
|
||||
-------Table Start--------
|
||||
196c8e04-d288-4bae-b6a5-6f91e415c2cf
|
||||
[['CPT 59400-Global Obstetric care with vaginal delivery', '$1700.00'], ['CPT 59510-Global Obstetric care with Cesarean delivery', '$1700.00']]
|
||||
Compensation for obstetrical services shall be at the lesser of the PPG's billed charges, or:
|
||||
-------Table End--------
|
||||
-------Table Start--------
|
||||
e5b15a0a-377a-4534-b3aa-ad5a33399276
|
||||
[['00955 - Continuous epidural, labor and vaginal delivery', '5 units'], ['00857 - Continuous epidural, labor and C-Section', '7 units'], ['00850 - Planned C-Section', '7 units']]
|
||||
Compensation for obstetrical services shall be at the lesser of the PPG's billed charges, or: BASE UNITS:
|
||||
-------Table End--------
|
||||
-------Table Start--------
|
||||
267e60c0-1116-4569-8c82-0e2fc14ffeb7
|
||||
[[None, None], ['Start up time:', 'up to three units for first hour of labor time, plus'], ['Labor time:', 'two units for each additional hour of labor, plus'], ['Surgery time:', 'one unit for each fifteen minute interval of surgical time if labor goes: into C-Section, or of planned C-Section']]
|
||||
Compensation for obstetrical services shall be at the lesser of the PPG's billed charges, or: BASE UNITS: TIME UNITS:
|
||||
-------Table End--------
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
"queryorchestration/internal/serviceconfig/objectstore"
|
||||
"queryorchestration/internal/serviceconfig/queue/querysync"
|
||||
"queryorchestration/internal/serviceconfig/textract"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
awstextract "github.com/aws/aws-sdk-go-v2/service/textract"
|
||||
"github.com/aws/aws-sdk-go-v2/service/textract/types"
|
||||
@@ -87,21 +89,40 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
slog.Info("detecting text")
|
||||
slog.Info("detecting text", "page_count", count)
|
||||
|
||||
startTime := time.Now()
|
||||
allResults := map[string][]awstextract.AnalyzeDocumentOutput{}
|
||||
allResults["base"] = make([]awstextract.AnalyzeDocumentOutput, count)
|
||||
allResults["table"] = []awstextract.AnalyzeDocumentOutput{}
|
||||
var wg sync.WaitGroup
|
||||
for i := range count {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
slog.Info("getting page", "index", i)
|
||||
|
||||
result, err := textSvc.GetBasePage(ctx, pdf, i)
|
||||
if err != nil {
|
||||
slog.Error("error detecting text", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
allResults["base"][i] = result
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
allResults["table"] = []awstextract.AnalyzeDocumentOutput{}
|
||||
for i, result := range allResults["base"] {
|
||||
hasTable := false
|
||||
for _, block := range result.Blocks {
|
||||
feature := textSvc.GetBlockFeature(block)
|
||||
if feature == documenttext.FeatureTable {
|
||||
if block.BlockType == types.BlockTypeLayoutTable {
|
||||
hasTable = true
|
||||
}
|
||||
}
|
||||
|
||||
if hasTable {
|
||||
slog.Info("getting table", "index", i)
|
||||
pageBytes, err := pdf.GetPageAsPNG(ctx, i)
|
||||
if err != nil {
|
||||
slog.Error("error getting page", "error", err)
|
||||
@@ -124,9 +145,6 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
allResults["base"][i] = result
|
||||
}
|
||||
|
||||
generatedBase := "generated"
|
||||
|
||||
if _, err := root.Stat(generatedBase); os.IsNotExist(err) {
|
||||
@@ -159,5 +177,5 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("Successfully generated " + outputFilename)
|
||||
slog.Info("extracted text", "output", outputFilename, "time", time.Since(startTime))
|
||||
}
|
||||
|
||||
+2
-1
@@ -55,7 +55,8 @@
|
||||
"gomarkdoc@1.1.0",
|
||||
"go@1.24.0",
|
||||
"sqlcheck@1.3",
|
||||
"docker-client@27.3.1"
|
||||
"docker-client@27.3.1",
|
||||
"gotestsum@latest"
|
||||
],
|
||||
"shell": {
|
||||
"init_hook": [
|
||||
|
||||
+48
@@ -401,6 +401,54 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"gotestsum@latest": {
|
||||
"last_modified": "2025-04-05T00:48:53Z",
|
||||
"resolved": "github:NixOS/nixpkgs/250b695f41e0e2f5afbf15c6b12480de1fe0001b#gotestsum",
|
||||
"source": "devbox-search",
|
||||
"version": "1.12.0-unstable-2024-09-17",
|
||||
"systems": {
|
||||
"aarch64-darwin": {
|
||||
"outputs": [
|
||||
{
|
||||
"name": "out",
|
||||
"path": "/nix/store/93kwis02c81bwh382s1vdmsqp7s886fl-gotestsum-1.12.0-unstable-2024-09-17",
|
||||
"default": true
|
||||
}
|
||||
],
|
||||
"store_path": "/nix/store/93kwis02c81bwh382s1vdmsqp7s886fl-gotestsum-1.12.0-unstable-2024-09-17"
|
||||
},
|
||||
"aarch64-linux": {
|
||||
"outputs": [
|
||||
{
|
||||
"name": "out",
|
||||
"path": "/nix/store/hmil65sxh60c0mx2f1b41b883dmni5x9-gotestsum-1.12.0-unstable-2024-09-17",
|
||||
"default": true
|
||||
}
|
||||
],
|
||||
"store_path": "/nix/store/hmil65sxh60c0mx2f1b41b883dmni5x9-gotestsum-1.12.0-unstable-2024-09-17"
|
||||
},
|
||||
"x86_64-darwin": {
|
||||
"outputs": [
|
||||
{
|
||||
"name": "out",
|
||||
"path": "/nix/store/1gj7gmd3jsxcn8sxa2zac13f7mh4frx4-gotestsum-1.12.0-unstable-2024-09-17",
|
||||
"default": true
|
||||
}
|
||||
],
|
||||
"store_path": "/nix/store/1gj7gmd3jsxcn8sxa2zac13f7mh4frx4-gotestsum-1.12.0-unstable-2024-09-17"
|
||||
},
|
||||
"x86_64-linux": {
|
||||
"outputs": [
|
||||
{
|
||||
"name": "out",
|
||||
"path": "/nix/store/5iq2g0zd9xiss7px89mdha3qlcws0cl4-gotestsum-1.12.0-unstable-2024-09-17",
|
||||
"default": true
|
||||
}
|
||||
],
|
||||
"store_path": "/nix/store/5iq2g0zd9xiss7px89mdha3qlcws0cl4-gotestsum-1.12.0-unstable-2024-09-17"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gotools@0.25.0": {
|
||||
"last_modified": "2024-12-23T21:10:33Z",
|
||||
"resolved": "github:NixOS/nixpkgs/de1864217bfa9b5845f465e771e0ecb48b30e02d#gotools",
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"queryorchestration/internal/serviceconfig"
|
||||
"queryorchestration/internal/test"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -119,21 +120,7 @@ func TestListClientDocumentIDs(t *testing.T) {
|
||||
}, ids)
|
||||
}
|
||||
|
||||
func TestClientSync(t *testing.T) {
|
||||
t.Parallel()
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping long test in short mode")
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
cfg := &serviceconfig.BaseConfig{}
|
||||
net := test.DepNetwork.Get(t, ctx)
|
||||
_ = test.CreateDB(t, ctx, cfg, net, &test.CreateDatabaseConfig{
|
||||
RunMigrations: true,
|
||||
})
|
||||
|
||||
queries := cfg.GetDBQueries()
|
||||
|
||||
func createDependentQueries(t testing.TB, ctx context.Context, queries *repository.Queries) (uuid.UUID, uuid.UUID) {
|
||||
contextQueryID, err := queries.CreateQuery(ctx, repository.Querytype(repository.QuerytypeContextFull))
|
||||
require.NoError(t, err)
|
||||
contextQueryVersion, err := queries.AddLatestQueryVersion(ctx, contextQueryID)
|
||||
@@ -159,8 +146,12 @@ func TestClientSync(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
return contextQueryID, jsonQueryID
|
||||
}
|
||||
|
||||
func createClientWithCollector(t testing.TB, ctx context.Context, queries *repository.Queries) string {
|
||||
clientId := "EXAMPLE"
|
||||
err = queries.CreateClient(ctx, &repository.CreateClientParams{
|
||||
err := queries.CreateClient(ctx, &repository.CreateClientParams{
|
||||
Name: "example_client",
|
||||
ID: clientId,
|
||||
})
|
||||
@@ -173,10 +164,34 @@ func TestClientSync(t *testing.T) {
|
||||
Clientid: clientId,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = queries.AddCollectorQuery(ctx, &repository.AddCollectorQueryParams{
|
||||
|
||||
return clientId
|
||||
}
|
||||
|
||||
func TestClientSync(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping long test in short mode")
|
||||
}
|
||||
|
||||
t.Run("document fail clean", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
|
||||
cfg := &serviceconfig.BaseConfig{}
|
||||
net := test.DepNetwork.Get(t, ctx)
|
||||
_ = test.CreateDB(t, ctx, cfg, net, &test.CreateDatabaseConfig{
|
||||
RunMigrations: true,
|
||||
})
|
||||
|
||||
queries := cfg.GetDBQueries()
|
||||
|
||||
_, jsonQueryID := createDependentQueries(t, ctx, queries)
|
||||
clientId := createClientWithCollector(t, ctx, queries)
|
||||
|
||||
err := queries.AddCollectorQuery(ctx, &repository.AddCollectorQueryParams{
|
||||
Clientid: clientId,
|
||||
Queryid: jsonQueryID,
|
||||
Addedversion: collectorVersion,
|
||||
Addedversion: 1,
|
||||
Name: "first_key",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -185,9 +200,6 @@ func TestClientSync(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.True(t, isSynced)
|
||||
|
||||
bucket := "example_bucket"
|
||||
|
||||
t.Run("document fail clean", func(t *testing.T) {
|
||||
documentID, err := queries.CreateDocument(ctx, &repository.CreateDocumentParams{
|
||||
Clientid: clientId,
|
||||
Hash: "example_noclean",
|
||||
@@ -235,6 +247,34 @@ func TestClientSync(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("valid extraction", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
|
||||
cfg := &serviceconfig.BaseConfig{}
|
||||
net := test.DepNetwork.Get(t, ctx)
|
||||
_ = test.CreateDB(t, ctx, cfg, net, &test.CreateDatabaseConfig{
|
||||
RunMigrations: true,
|
||||
})
|
||||
|
||||
queries := cfg.GetDBQueries()
|
||||
|
||||
contextQueryID, jsonQueryID := createDependentQueries(t, ctx, queries)
|
||||
clientId := createClientWithCollector(t, ctx, queries)
|
||||
|
||||
err := queries.AddCollectorQuery(ctx, &repository.AddCollectorQueryParams{
|
||||
Clientid: clientId,
|
||||
Queryid: jsonQueryID,
|
||||
Addedversion: 1,
|
||||
Name: "first_key",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
isSynced, err := queries.IsClientSynced(ctx, &clientId)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, isSynced)
|
||||
|
||||
bucket := "example_bucket"
|
||||
|
||||
documentID, err := queries.CreateDocument(ctx, &repository.CreateDocumentParams{
|
||||
Clientid: clientId,
|
||||
Hash: "example_hash",
|
||||
@@ -320,7 +360,7 @@ func TestClientSync(t *testing.T) {
|
||||
Queryid: contextQueryID,
|
||||
Value: "example_context",
|
||||
Textentryid: textId,
|
||||
Queryversion: contextQueryVersion,
|
||||
Queryversion: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -340,7 +380,7 @@ func TestClientSync(t *testing.T) {
|
||||
Queryid: jsonQueryID,
|
||||
Value: "json_value",
|
||||
Textentryid: textId,
|
||||
Queryversion: jsonQueryVersion,
|
||||
Queryversion: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -421,7 +461,7 @@ func TestClientSync(t *testing.T) {
|
||||
Queryid: jsonQueryID,
|
||||
Value: "updated_context_value",
|
||||
Textentryid: textId,
|
||||
Queryversion: jsonQueryVersion,
|
||||
Queryversion: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -818,7 +858,7 @@ func TestClientSync(t *testing.T) {
|
||||
Queryid: jsonQueryID,
|
||||
Value: "json_with_super",
|
||||
Textentryid: textThreeId,
|
||||
Queryversion: jsonQueryVersion,
|
||||
Queryversion: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ type DocInitConfig struct {
|
||||
documentsync.DocSyncConfig
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
func TestNewDocumentInitService(t *testing.T) {
|
||||
svc := New(&DocInitConfig{})
|
||||
assert.NotNil(t, svc)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
func TestNewDocumentService(t *testing.T) {
|
||||
svc := document.New(nil)
|
||||
assert.NotNil(t, svc)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ type DocInitConfig struct {
|
||||
documentinit.DocInitConfig
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
func TestNewDocumentStoreService(t *testing.T) {
|
||||
svc := New(&DocInitConfig{})
|
||||
assert.NotNil(t, svc)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ type DocSyncConfig struct {
|
||||
documentclean.DocCleanConfig
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
func TestNewDocumentSyncService(t *testing.T) {
|
||||
svc := documentsync.New(&DocSyncConfig{}, &documentsync.Services{})
|
||||
assert.NotNil(t, svc)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package documenttext
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -49,8 +50,9 @@ func TestExecuteExtract(t *testing.T) {
|
||||
EntityID: cleanId,
|
||||
}
|
||||
keyStr := key.String()
|
||||
textractFile := "../../../assets/sampleGeneration/generated/helloWorld.gen"
|
||||
textractBaseOut := getTextractFileResponse(t, textractFile)
|
||||
root, err := os.OpenRoot("../../../assets")
|
||||
require.NoError(t, err)
|
||||
textractBaseOut := getTextractFileResponse(t, "sampleGeneration/generated/helloWorld.gen", root)
|
||||
|
||||
mimetype := repository.NullCleanmimetype{
|
||||
Valid: true,
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -68,8 +69,9 @@ func TestCreate(t *testing.T) {
|
||||
EntityID: cleanId,
|
||||
}
|
||||
keyStr := key.String()
|
||||
textractFile := "../../../assets/sampleGeneration/generated/helloWorld.gen"
|
||||
textractBaseOut := getTextractFileResponse(t, textractFile)
|
||||
root, err := os.OpenRoot("../../../assets")
|
||||
require.NoError(t, err)
|
||||
textractBaseOut := getTextractFileResponse(t, "sampleGeneration/generated/helloWorld.gen", root)
|
||||
|
||||
mimetype := repository.NullCleanmimetype{
|
||||
Valid: true,
|
||||
|
||||
@@ -50,21 +50,15 @@ func (s *Service) getPageElements(ctx context.Context, document documenttypes.Fi
|
||||
continue
|
||||
}
|
||||
|
||||
if s.isLayout(blockMap[id].BlockType) {
|
||||
lines = append(lines, id)
|
||||
f := true
|
||||
found[id] = &f
|
||||
}
|
||||
|
||||
if blockMap[id].BlockType == types.BlockTypeLayoutTable {
|
||||
hasTable = true
|
||||
}
|
||||
if blockMap[id].BlockType == types.BlockTypeLayoutTable ||
|
||||
blockMap[id].BlockType == types.BlockTypeLayoutList {
|
||||
for _, childId := range s.getChildIds(blockMap[id]) {
|
||||
f := false
|
||||
found[childId] = &f
|
||||
}
|
||||
}
|
||||
|
||||
s.removeChildren(blockMap[id], blockMap, &found)
|
||||
}
|
||||
|
||||
var tables []uuid.UUID
|
||||
@@ -81,18 +75,12 @@ func (s *Service) getPageElements(ctx context.Context, document documenttypes.Fi
|
||||
return lines, tables, tableBlockMap, found, nil
|
||||
}
|
||||
|
||||
func (s *Service) isLayout(blockType types.BlockType) bool {
|
||||
return blockType == types.BlockTypeLayoutText ||
|
||||
blockType == types.BlockTypeLayoutTitle ||
|
||||
blockType == types.BlockTypeLayoutHeader ||
|
||||
blockType == types.BlockTypeLayoutFooter ||
|
||||
blockType == types.BlockTypeLayoutSectionHeader ||
|
||||
blockType == types.BlockTypeLayoutPageNumber ||
|
||||
blockType == types.BlockTypeLayoutList ||
|
||||
blockType == types.BlockTypeLayoutFigure ||
|
||||
blockType == types.BlockTypeLayoutTable ||
|
||||
blockType == types.BlockTypeLayoutKeyValue ||
|
||||
blockType == types.BlockTypeSignature
|
||||
func (s *Service) removeChildren(block types.Block, blockMap map[uuid.UUID]types.Block, found *map[uuid.UUID]*bool) {
|
||||
for _, childId := range s.getChildIds(block) {
|
||||
f := false
|
||||
(*found)[childId] = &f
|
||||
s.removeChildren(blockMap[childId], blockMap, found)
|
||||
}
|
||||
}
|
||||
|
||||
type buildParams struct {
|
||||
@@ -148,6 +136,15 @@ func (s *Service) addComponentText(ctx context.Context, block types.Block, block
|
||||
case types.BlockTypeSignature:
|
||||
params.numOfSignatures++
|
||||
case types.BlockTypeLayoutTable:
|
||||
if len(tables) <= params.currentTable {
|
||||
for _, child := range s.getChildIds(block) {
|
||||
err := s.addComponentText(ctx, blockMap[child], blockMap, tables, tableBlockMap, params, builder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
tableId := tables[params.currentTable]
|
||||
params.currentTable++
|
||||
tableBlock := tableBlockMap[tableId]
|
||||
@@ -155,6 +152,8 @@ func (s *Service) addComponentText(ctx context.Context, block types.Block, block
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
slog.Debug("uncaught component", "type", block.BlockType)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -3,8 +3,8 @@ package documenttext
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -35,8 +35,9 @@ func TestGetBasePage(t *testing.T) {
|
||||
pdf, err := documenttypes.NewPDFFromReader(strings.NewReader(pdfHelloWorld))
|
||||
require.NoError(t, err)
|
||||
|
||||
textractFile := "../../../assets/sampleGeneration/generated/helloWorld.gen"
|
||||
textractBaseOut := getTextractFileResponse(t, textractFile)
|
||||
root, err := os.OpenRoot("../../../assets")
|
||||
require.NoError(t, err)
|
||||
textractBaseOut := getTextractFileResponse(t, "sampleGeneration/generated/helloWorld.gen", root)
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
@@ -59,121 +60,39 @@ func TestGetBasePage(t *testing.T) {
|
||||
|
||||
func TestGetDocumentText(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("Hello World", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cfg := DocTextConfig{}
|
||||
svc := Service{
|
||||
cfg: &cfg,
|
||||
}
|
||||
|
||||
t.Run("Hello World", func(t *testing.T) {
|
||||
mockTextract := textractmock.NewMockTextractClient(t)
|
||||
cfg.TextractClient = mockTextract
|
||||
sent := 0
|
||||
|
||||
pdf, err := documenttypes.NewPDFFromReader(strings.NewReader(pdfHelloWorld))
|
||||
require.NoError(t, err)
|
||||
textractBaseOut, pdf, txtFile, close := getFiles(t, "sampleGeneration", "helloWorld")
|
||||
defer close()
|
||||
|
||||
textractFile := "../../../assets/sampleGeneration/generated/helloWorld.gen"
|
||||
textractBaseOut := getTextractFileResponse(t, textractFile)
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == 0 {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["base"][0], nil).Once()
|
||||
textExpectations(t, mockTextract, textractBaseOut)
|
||||
|
||||
text, err := svc.getDocumentText(ctx, pdf)
|
||||
require.NoError(t, err)
|
||||
expected := `Start of Page No. = 1
|
||||
|
||||
Hello World!
|
||||
|
||||
|
||||
`
|
||||
assertStringToReader(t, expected, text)
|
||||
assertReaders(t, txtFile, text)
|
||||
})
|
||||
|
||||
t.Run("sampleOne - cnc_01-06", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cfg := DocTextConfig{}
|
||||
svc := Service{
|
||||
cfg: &cfg,
|
||||
}
|
||||
mockTextract := textractmock.NewMockTextractClient(t)
|
||||
cfg.TextractClient = mockTextract
|
||||
sent := 0
|
||||
|
||||
textractFile := "../../../assets/sampleOne/generated/cnc_01-06.gen"
|
||||
textractBaseOut := getTextractFileResponse(t, textractFile)
|
||||
textractBaseOut, pdf, txtFile, close := getFiles(t, "sampleOne", "cnc_01-06")
|
||||
defer close()
|
||||
|
||||
pdfFile, err := os.Open("../../../assets/sampleOne/cnc_01-06.pdf")
|
||||
require.NoError(t, err)
|
||||
defer pdfFile.Close()
|
||||
|
||||
pdf, err := documenttypes.NewPDFFromReader(pdfFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
txtFile, err := os.Open("../../../assets/sampleOne/cnc_01-06.txt")
|
||||
require.NoError(t, err)
|
||||
defer txtFile.Close()
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == 0 {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["base"][0], nil).Once()
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == 1 {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["base"][1], nil).Once()
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == 2 {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["base"][2], nil).Once()
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == 3 {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["base"][3], nil).Once()
|
||||
textExpectations(t, mockTextract, textractBaseOut)
|
||||
|
||||
text, err := svc.getDocumentText(ctx, pdf)
|
||||
require.NoError(t, err)
|
||||
@@ -181,113 +100,120 @@ Hello World!
|
||||
assertReaders(t, txtFile, text)
|
||||
})
|
||||
t.Run("sampleOne - hn_0109", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cfg := DocTextConfig{}
|
||||
svc := Service{
|
||||
cfg: &cfg,
|
||||
}
|
||||
mockTextract := textractmock.NewMockTextractClient(t)
|
||||
cfg.TextractClient = mockTextract
|
||||
sent := 0
|
||||
|
||||
textractFile := "../../../assets/sampleOne/generated/hn_0109.gen"
|
||||
textractBaseOut := getTextractFileResponse(t, textractFile)
|
||||
textractBaseOut, pdf, txtFile, close := getFiles(t, "sampleOne", "hn_0109")
|
||||
defer close()
|
||||
|
||||
pdfFile, err := os.Open("../../../assets/sampleOne/hn_0109.pdf")
|
||||
require.NoError(t, err)
|
||||
defer pdfFile.Close()
|
||||
|
||||
pdf, err := documenttypes.NewPDFFromReader(pdfFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
txtFile, err := os.Open("../../../assets/sampleOne/hn_0109.txt")
|
||||
require.NoError(t, err)
|
||||
defer txtFile.Close()
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == 0 {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["base"][0], nil).Once()
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == 1 {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["base"][1], nil).Once()
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == 2 && in.FeatureTypes[0] == types.FeatureTypeTables {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["table"][0], nil).Once()
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == 3 {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["base"][2], nil).Once()
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == 4 && in.FeatureTypes[0] == types.FeatureTypeTables {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["table"][1], nil).Once()
|
||||
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == 5 {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["base"][3], nil).Once()
|
||||
textExpectations(t, mockTextract, textractBaseOut)
|
||||
|
||||
text, err := svc.getDocumentText(ctx, pdf)
|
||||
require.NoError(t, err)
|
||||
|
||||
assertReaders(t, txtFile, text)
|
||||
})
|
||||
t.Run("sampleOne - hn23-70", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cfg := DocTextConfig{}
|
||||
svc := Service{
|
||||
cfg: &cfg,
|
||||
}
|
||||
mockTextract := textractmock.NewMockTextractClient(t)
|
||||
cfg.TextractClient = mockTextract
|
||||
|
||||
textractBaseOut, pdf, txtFile, close := getFiles(t, "sampleOne", "hn_23-70")
|
||||
defer close()
|
||||
|
||||
textExpectations(t, mockTextract, textractBaseOut)
|
||||
|
||||
text, err := svc.getDocumentText(ctx, pdf)
|
||||
require.NoError(t, err)
|
||||
|
||||
assertReaders(t, txtFile, text)
|
||||
})
|
||||
}
|
||||
|
||||
func getFiles(t testing.TB, sample string, filename string) (map[string][]textract.AnalyzeDocumentOutput, *documenttypes.PDF, *os.File, func()) {
|
||||
root, err := os.OpenRoot("../../../assets")
|
||||
require.NoError(t, err)
|
||||
root, err = root.OpenRoot(sample)
|
||||
require.NoError(t, err)
|
||||
|
||||
textractFile, err := root.Open(fmt.Sprintf("generated/%s.gen", filename))
|
||||
require.NoError(t, err)
|
||||
defer textractFile.Close()
|
||||
|
||||
decoder := json.NewDecoder(textractFile)
|
||||
var out map[string][]textract.AnalyzeDocumentOutput
|
||||
err = decoder.Decode(&out)
|
||||
require.NoError(t, err)
|
||||
|
||||
pdfFile, err := root.Open(fmt.Sprintf("%s.pdf", filename))
|
||||
require.NoError(t, err)
|
||||
|
||||
pdf, err := documenttypes.NewPDFFromReader(pdfFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
txtFile, err := root.Open(fmt.Sprintf("%s.txt", filename))
|
||||
require.NoError(t, err)
|
||||
|
||||
return out, pdf, txtFile, func() {
|
||||
pdfFile.Close()
|
||||
txtFile.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func textExpectations(t testing.TB, mockTextract *textractmock.MockTextractClient, textractBaseOut map[string][]textract.AnalyzeDocumentOutput) {
|
||||
sent := 0
|
||||
tableIndex := 0
|
||||
for i := range len(textractBaseOut["base"]) {
|
||||
curr := i + tableIndex
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == curr {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["base"][i], nil).Once()
|
||||
|
||||
hasTable := false
|
||||
for _, t := range textractBaseOut["base"][i].Blocks {
|
||||
if t.BlockType == types.BlockTypeLayoutTable {
|
||||
hasTable = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hasTable {
|
||||
curr := i + tableIndex + 1
|
||||
mockTextract.EXPECT().
|
||||
AnalyzeDocument(
|
||||
mock.Anything,
|
||||
mock.MatchedBy(func(in *textract.AnalyzeDocumentInput) bool {
|
||||
if sent == curr && in.FeatureTypes[0] == types.FeatureTypeTables {
|
||||
sent++
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}),
|
||||
mock.Anything,
|
||||
).
|
||||
Return(&textractBaseOut["table"][tableIndex], nil).Once()
|
||||
tableIndex++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBlockMap(t *testing.T) {
|
||||
@@ -423,8 +349,8 @@ page three
|
||||
})
|
||||
}
|
||||
|
||||
func getTextractFileResponse(t *testing.T, filename string) map[string][]textract.AnalyzeDocumentOutput {
|
||||
file, err := os.Open(filename)
|
||||
func getTextractFileResponse(t testing.TB, filename string, root *os.Root) map[string][]textract.AnalyzeDocumentOutput {
|
||||
file, err := root.Open(filename)
|
||||
require.NoError(t, err)
|
||||
defer file.Close()
|
||||
|
||||
@@ -436,17 +362,7 @@ func getTextractFileResponse(t *testing.T, filename string) map[string][]textrac
|
||||
return out
|
||||
}
|
||||
|
||||
func assertStringToReader(t *testing.T, expected string, actual io.Reader) {
|
||||
actualBytes, err := io.ReadAll(actual)
|
||||
require.NoError(t, err)
|
||||
actualStr := string(actualBytes)
|
||||
if !assert.Equal(t, expected, actualStr) {
|
||||
diff := cmp.Diff(expected, actualStr)
|
||||
t.Logf("Detailed diff (-expected +actual):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func assertReaders(t *testing.T, expected io.Reader, actual io.Reader) {
|
||||
func assertReaders(t testing.TB, expected io.Reader, actual io.Reader) {
|
||||
actualBytes, err := io.ReadAll(actual)
|
||||
require.NoError(t, err)
|
||||
actualStr := string(actualBytes)
|
||||
@@ -461,52 +377,6 @@ func assertReaders(t *testing.T, expected io.Reader, actual io.Reader) {
|
||||
}
|
||||
}
|
||||
|
||||
func levenshteinDistance(s1, s2 string) int {
|
||||
rows, cols := len(s1)+1, len(s2)+1
|
||||
dist := make([][]int, rows)
|
||||
for i := range dist {
|
||||
dist[i] = make([]int, cols)
|
||||
}
|
||||
|
||||
for i := 0; i < rows; i++ {
|
||||
dist[i][0] = i
|
||||
}
|
||||
for j := 0; j < cols; j++ {
|
||||
dist[0][j] = j
|
||||
}
|
||||
|
||||
for i := 1; i < rows; i++ {
|
||||
for j := 1; j < cols; j++ {
|
||||
cost := 1
|
||||
if s1[i-1] == s2[j-1] {
|
||||
cost = 0
|
||||
}
|
||||
dist[i][j] = min(
|
||||
dist[i-1][j]+1,
|
||||
dist[i][j-1]+1,
|
||||
dist[i-1][j-1]+cost,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return dist[rows-1][cols-1]
|
||||
}
|
||||
|
||||
func calculateSimilarityPercentage(s1, s2 string) float64 {
|
||||
distance := levenshteinDistance(s1, s2)
|
||||
maxLen := math.Max(float64(len(s1)), float64(len(s2)))
|
||||
|
||||
if maxLen == 0 {
|
||||
return 100.0
|
||||
}
|
||||
|
||||
return 100.0 * (1.0 - float64(distance)/maxLen)
|
||||
}
|
||||
|
||||
func AreSimilar(s1, s2 string, threshold float64) bool {
|
||||
return calculateSimilarityPercentage(s1, s2) >= threshold
|
||||
}
|
||||
|
||||
const pdfHelloWorld = `%PDF-1.4
|
||||
%����
|
||||
1 0 obj
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"sync"
|
||||
|
||||
"github.com/gen2brain/go-fitz"
|
||||
"github.com/pdfcpu/pdfcpu/pkg/api"
|
||||
@@ -22,6 +23,7 @@ type PDF struct {
|
||||
minDimension int
|
||||
minDPI int
|
||||
pngDPI int
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -61,8 +63,20 @@ func NewPDF(buf io.ReadSeeker) *PDF {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PDF) read(ctx context.Context) (*model.Context, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
_, err := s.pdf.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pdfcpu.ReadWithContext(ctx, s.pdf, s.config)
|
||||
}
|
||||
|
||||
func (s *PDF) GetPageCount(ctx context.Context) (int, error) {
|
||||
pdfCtx, err := pdfcpu.ReadWithContext(ctx, s.pdf, s.config)
|
||||
pdfCtx, err := s.read(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -76,7 +90,7 @@ func (s *PDF) GetPageCount(ctx context.Context) (int, error) {
|
||||
}
|
||||
|
||||
func (s *PDF) GetPage(ctx context.Context, index int) ([]byte, error) {
|
||||
pdfCtx, err := pdfcpu.ReadWithContext(ctx, s.pdf, s.config)
|
||||
pdfCtx, err := s.read(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -117,7 +131,7 @@ func (s *PDF) GetPageAsPNG(ctx context.Context, index int) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (s *PDF) IsCorrupt(ctx context.Context) *InvalidDocumentReason {
|
||||
pdfCtx, err := pdfcpu.ReadWithContext(ctx, s.pdf, s.config)
|
||||
pdfCtx, err := s.read(ctx)
|
||||
if err != nil {
|
||||
reason := InvalidDocumentRead
|
||||
return &reason
|
||||
@@ -158,12 +172,6 @@ func (s *PDF) isValidDimensions(pdfCtx *model.Context) *InvalidDocumentReason {
|
||||
return &reason
|
||||
}
|
||||
|
||||
_, err = s.pdf.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
reason := InvalidDocumentRead
|
||||
return &reason
|
||||
}
|
||||
|
||||
pageSet := types.IntSet{}
|
||||
for pageNum := 1; pageNum <= pdfCtx.PageCount; pageNum++ {
|
||||
pageSet[pageNum] = true
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
func TestNewExportService(t *testing.T) {
|
||||
svc := export.New()
|
||||
assert.NotNil(t, svc)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
func TestNewAPI(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping long test in short mode")
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ type TestConfig struct {
|
||||
objectstore.ObjectStoreConfig
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
func TestNewRunner(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping long test in short mode")
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
func TestNewServer(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping long test in short mode")
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ func CreateDB(t testing.TB, ctx context.Context, cfg serviceconfig.ConfigProvide
|
||||
"POSTGRES_USER": user,
|
||||
"POSTGRES_PASSWORD": pass,
|
||||
},
|
||||
Cmd: []string{"postgres", "-c", "max_connections=1000"},
|
||||
ExposedPorts: []string{port.Port()},
|
||||
WaitingFor: wait.ForAll(
|
||||
wait.ForExposedPort(),
|
||||
|
||||
@@ -269,6 +269,7 @@ func NormaliseAlias(fullName string) string {
|
||||
name := strings.ToLower(fullName)
|
||||
name = strings.ReplaceAll(name, "/", "_")
|
||||
name = strings.ReplaceAll(name, " ", "_")
|
||||
name = strings.ReplaceAll(name, "-", "_")
|
||||
return name
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ func TestCreateFullDependencies(t *testing.T) {
|
||||
cleanup()
|
||||
}
|
||||
|
||||
func TestDepNetworkGet(t *testing.T) {
|
||||
func TestCreateFullNetwork(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping long test in short mode")
|
||||
}
|
||||
|
||||
+4
-3
@@ -9,7 +9,8 @@ vars:
|
||||
API: "./api/..."
|
||||
PKG: "./pkg/..."
|
||||
CMD: "./cmd/..."
|
||||
PARALLEL: 1
|
||||
UNIT_PARALLEL: 8
|
||||
E2E_PARALLEL: 1
|
||||
# yamllint disable-line rule:line-length
|
||||
EXCLUDED_FILES: ".gen.go|internal/serviceconfig/observability/prometheus/generator/main.go"
|
||||
|
||||
@@ -33,7 +34,7 @@ tasks:
|
||||
- task: mocks:generate
|
||||
- mkdir -p {{.OUT_DIR}}
|
||||
- |
|
||||
go test -parallel {{.PARALLEL}} \
|
||||
go test -parallel {{.UNIT_PARALLEL}} \
|
||||
{{.INTERNAL}} {{.API}} {{.CLI_ARGS}}
|
||||
unit:short:
|
||||
cmds:
|
||||
@@ -98,4 +99,4 @@ tasks:
|
||||
deps:
|
||||
- docker:build
|
||||
cmds:
|
||||
- go test -count=1 -parallel {{.PARALLEL}} ./test/...
|
||||
- go test -count=1 -parallel {{.E2E_PARALLEL}} ./test/...
|
||||
|
||||
Reference in New Issue
Block a user