Compare commits

...

3 commits

Author SHA1 Message Date
feibisi
b963cf90f3 Remove Alipay EasySDK and related files
Deleted all Alipay EasySDK vendor libraries (PHP, Java, C#), related assets, CSS/JS, and configuration files. Added new gateway enablement and subscription UI files, and updated main plugin classes. This refactors the codebase to remove dependency on Alipay EasySDK and associated payment methods.
2025-10-08 15:07:18 +08:00
feibisi
8e42099433 Update README files with enhanced features and documentation
Expanded both English and Chinese README files with detailed feature lists, installation instructions, compatibility notes, FAQ, support, and contribution guidelines. Added badges for WordPress, WooCommerce, and license, and clarified plugin scope and advanced capabilities for Woo Alipay.
2025-10-08 11:30:06 +08:00
feibisi
38a677fcfe Add English README and update Chinese README
Added a new English documentation file (README-EN.md) for the Woo Alipay WooCommerce payment gateway plugin. Updated the original README.md to improve and clarify the Chinese documentation, including more detailed setup, configuration, and template override instructions.
2025-10-08 11:24:35 +08:00
618 changed files with 948 additions and 81589 deletions

View file

@ -0,0 +1,202 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="100%" viewBox="0 0 265 265" enable-background="new 0 0 265 265" xml:space="preserve">
<path fill="#F5F7F7" opacity="1.000000" stroke="none"
d="
M183.000000,266.000000
C122.000000,266.000000 61.500000,266.000000 1.000000,266.000000
C1.000000,177.666672 1.000000,89.333336 1.000000,1.000000
C89.333336,1.000000 177.666672,1.000000 266.000000,1.000000
C266.000000,89.333336 266.000000,177.666672 266.000000,266.000000
C238.500000,266.000000 211.000000,266.000000 183.000000,266.000000
M94.933517,140.248688
C88.576836,140.751221 86.521210,142.729355 86.444107,148.786041
C86.353195,155.927231 86.349190,163.071487 86.447525,170.212494
C86.527962,176.052734 88.864227,178.471405 94.594826,178.562164
C102.067513,178.680542 109.544624,178.673477 117.017624,178.566406
C122.404800,178.489227 124.664230,176.319885 124.760513,171.010956
C124.899048,163.372803 124.886459,155.728882 124.767349,148.090088
C124.679726,142.470688 122.435028,140.326935 116.776085,140.266327
C109.800636,140.191620 102.823769,140.248062 94.933517,140.248688
M94.044777,86.222275
C88.831299,86.320442 86.533348,89.326210 86.460716,94.188850
C86.348717,101.686249 86.327766,109.188599 86.470680,116.684982
C86.570496,121.920876 88.997711,124.389366 94.173302,124.489525
C101.836166,124.637802 109.505371,124.618423 117.169258,124.500496
C122.517815,124.418205 124.676895,122.214584 124.761734,116.769913
C124.878548,109.272629 124.868591,101.771164 124.768234,94.273422
C124.689590,88.398010 122.454147,86.283966 116.434044,86.233253
C109.268753,86.172882 102.102570,86.219070 94.044777,86.222275
M152.036591,178.590424
C159.518356,178.588760 167.002182,178.693649 174.481186,178.549133
C179.750610,178.447342 182.062668,176.032654 182.109283,170.856949
C182.178177,163.209518 182.181351,155.560501 182.108612,147.913162
C182.061234,142.933090 179.790909,140.404800 174.919235,140.302521
C166.942245,140.135086 158.956879,140.144821 150.979446,140.302246
C146.274628,140.395096 144.066772,142.792496 144.015976,147.541397
C143.934174,155.188568 144.115067,162.839859 143.950562,170.484375
C143.840469,175.600464 146.026505,178.315231 152.036591,178.590424
M143.997375,109.464516
C143.998062,112.130241 144.013351,114.796059 143.996124,117.461670
C143.968857,121.682175 146.128052,124.246262 150.240677,124.357437
C158.729218,124.586899 167.232712,124.590675 175.721024,124.357597
C179.783051,124.246056 182.077408,121.699745 182.104370,117.525826
C182.156006,109.528976 182.131271,101.531540 182.116501,93.534386
C182.107803,88.831108 179.474945,86.397324 175.021072,86.288925
C167.028610,86.094414 159.026123,86.121849 151.031723,86.268639
C146.300262,86.355515 144.101288,88.735435 144.018051,93.482452
C143.930450,98.479164 143.997742,103.478592 143.997375,109.464516
M210.665131,84.776047
C209.944443,67.882568 199.516678,57.840118 182.624802,57.789463
C176.635086,57.771500 170.645035,57.753445 164.655579,57.797905
C159.571823,57.835640 156.711914,60.075039 156.651123,63.943302
C156.589798,67.843575 159.465805,70.369331 164.398178,70.447945
C171.051849,70.553993 177.713303,70.326553 184.362289,70.534210
C192.651230,70.793076 197.882477,76.288872 197.977234,84.591873
C198.051285,91.079956 198.098465,97.571877 197.955627,104.057648
C197.860123,108.394814 199.555466,111.210320 203.962234,111.720161
C207.845398,112.169418 210.546677,109.083549 210.637650,104.184509
C210.751938,98.030479 210.665512,91.872719 210.665131,84.776047
M193.085266,208.877869
C202.962463,204.856369 209.422546,197.853989 210.322998,187.042221
C210.997818,178.939255 210.703873,170.741745 210.565475,162.591003
C210.500046,158.737549 208.133209,156.208786 204.226181,156.314209
C200.139130,156.424484 197.961960,158.942139 197.985367,163.179504
C198.017548,169.006622 197.993408,174.834045 197.992340,180.661346
C197.990112,192.889023 193.370407,197.491867 181.099228,197.523682
C174.940094,197.539658 168.773697,197.418732 162.624695,197.685074
C158.986313,197.842682 156.255630,200.310150 156.903900,203.795975
C157.338898,206.134995 160.141449,209.777512 161.963562,209.825226
C172.060516,210.089691 182.181656,209.430801 193.085266,208.877869
M58.075195,89.531120
C58.074707,94.357040 58.025444,99.183578 58.087414,104.008698
C58.149727,108.860695 60.712017,112.044823 64.542152,111.749588
C69.021706,111.404305 70.800034,108.465698 70.815323,104.249390
C70.838249,97.925835 70.791443,91.601952 70.828224,85.278526
C70.883438,75.784592 76.052444,70.613098 85.649002,70.496323
C92.137924,70.417351 98.630325,70.543907 105.117104,70.397812
C109.084648,70.308456 111.837250,68.456711 112.019417,64.136826
C112.182884,60.260487 109.457390,57.859612 104.771713,57.810459
C97.450653,57.733662 90.019402,57.046982 82.841858,58.070518
C77.506760,58.831322 71.860703,60.997871 67.484756,64.122887
C59.347023,69.934341 57.344528,78.901474 58.075195,89.531120
M89.519699,210.216553
C94.345467,210.216370 99.171547,210.250793 103.996918,210.206680
C109.232590,210.158798 111.928757,208.089645 112.043839,204.136276
C112.165512,199.956879 109.409317,197.631393 103.896301,197.544510
C97.408028,197.442291 90.912674,197.658783 84.428391,197.466827
C76.118484,197.220825 70.928276,191.804367 70.836990,183.494003
C70.763878,176.838562 70.922905,170.179581 70.783600,163.526260
C70.688370,158.977814 68.013466,156.137939 64.323128,156.210587
C60.622017,156.283447 58.142273,159.150665 58.095528,163.711304
C58.022205,170.865921 57.889271,178.029922 58.181393,185.173615
C58.307373,188.254333 58.913387,191.533142 60.193012,194.311264
C65.741669,206.357651 75.600212,211.119110 89.519699,210.216553
z"/>
<path fill="#1B7AFF" opacity="1.000000" stroke="none"
d="
M95.390518,140.248260
C102.823769,140.248062 109.800636,140.191620 116.776085,140.266327
C122.435028,140.326935 124.679726,142.470688 124.767349,148.090088
C124.886459,155.728882 124.899048,163.372803 124.760513,171.010956
C124.664230,176.319885 122.404800,178.489227 117.017624,178.566406
C109.544624,178.673477 102.067513,178.680542 94.594826,178.562164
C88.864227,178.471405 86.527962,176.052734 86.447525,170.212494
C86.349190,163.071487 86.353195,155.927231 86.444107,148.786041
C86.521210,142.729355 88.576836,140.751221 95.390518,140.248260
z"/>
<path fill="#1979FF" opacity="1.000000" stroke="none"
d="
M94.490768,86.220688
C102.102570,86.219070 109.268753,86.172882 116.434044,86.233253
C122.454147,86.283966 124.689590,88.398010 124.768234,94.273422
C124.868591,101.771164 124.878548,109.272629 124.761734,116.769913
C124.676895,122.214584 122.517815,124.418205 117.169258,124.500496
C109.505371,124.618423 101.836166,124.637802 94.173302,124.489525
C88.997711,124.389366 86.570496,121.920876 86.470680,116.684982
C86.327766,109.188599 86.348717,101.686249 86.460716,94.188850
C86.533348,89.326210 88.831299,86.320442 94.490768,86.220688
z"/>
<path fill="#1A79FF" opacity="1.000000" stroke="none"
d="
M151.599731,178.586365
C146.026505,178.315231 143.840469,175.600464 143.950562,170.484375
C144.115067,162.839859 143.934174,155.188568 144.015976,147.541397
C144.066772,142.792496 146.274628,140.395096 150.979446,140.302246
C158.956879,140.144821 166.942245,140.135086 174.919235,140.302521
C179.790909,140.404800 182.061234,142.933090 182.108612,147.913162
C182.181351,155.560501 182.178177,163.209518 182.109283,170.856949
C182.062668,176.032654 179.750610,178.447342 174.481186,178.549133
C167.002182,178.693649 159.518356,178.588760 151.599731,178.586365
z"/>
<path fill="#1878FF" opacity="1.000000" stroke="none"
d="
M143.997375,108.970673
C143.997742,103.478592 143.930450,98.479164 144.018051,93.482452
C144.101288,88.735435 146.300262,86.355515 151.031723,86.268639
C159.026123,86.121849 167.028610,86.094414 175.021072,86.288925
C179.474945,86.397324 182.107803,88.831108 182.116501,93.534386
C182.131271,101.531540 182.156006,109.528976 182.104370,117.525826
C182.077408,121.699745 179.783051,124.246056 175.721024,124.357597
C167.232712,124.590675 158.729218,124.586899 150.240677,124.357437
C146.128052,124.246262 143.968857,121.682175 143.996124,117.461670
C144.013351,114.796059 143.998062,112.130241 143.997375,108.970673
z"/>
<path fill="#1A79FF" opacity="1.000000" stroke="none"
d="
M210.665405,85.246307
C210.665512,91.872719 210.751938,98.030479 210.637650,104.184509
C210.546677,109.083549 207.845398,112.169418 203.962234,111.720161
C199.555466,111.210320 197.860123,108.394814 197.955627,104.057648
C198.098465,97.571877 198.051285,91.079956 197.977234,84.591873
C197.882477,76.288872 192.651230,70.793076 184.362289,70.534210
C177.713303,70.326553 171.051849,70.553993 164.398178,70.447945
C159.465805,70.369331 156.589798,67.843575 156.651123,63.943302
C156.711914,60.075039 159.571823,57.835640 164.655579,57.797905
C170.645035,57.753445 176.635086,57.771500 182.624802,57.789463
C199.516678,57.840118 209.944443,67.882568 210.665405,85.246307
z"/>
<path fill="#1A79FF" opacity="1.000000" stroke="none"
d="
M192.689880,208.983002
C182.181656,209.430801 172.060516,210.089691 161.963562,209.825226
C160.141449,209.777512 157.338898,206.134995 156.903900,203.795975
C156.255630,200.310150 158.986313,197.842682 162.624695,197.685074
C168.773697,197.418732 174.940094,197.539658 181.099228,197.523682
C193.370407,197.491867 197.990112,192.889023 197.992340,180.661346
C197.993408,174.834045 198.017548,169.006622 197.985367,163.179504
C197.961960,158.942139 200.139130,156.424484 204.226181,156.314209
C208.133209,156.208786 210.500046,158.737549 210.565475,162.591003
C210.703873,170.741745 210.997818,178.939255 210.322998,187.042221
C209.422546,197.853989 202.962463,204.856369 192.689880,208.983002
z"/>
<path fill="#1B7AFF" opacity="1.000000" stroke="none"
d="
M58.075195,89.038673
C57.344528,78.901474 59.347023,69.934341 67.484756,64.122887
C71.860703,60.997871 77.506760,58.831322 82.841858,58.070518
C90.019402,57.046982 97.450653,57.733662 104.771713,57.810459
C109.457390,57.859612 112.182884,60.260487 112.019417,64.136826
C111.837250,68.456711 109.084648,70.308456 105.117104,70.397812
C98.630325,70.543907 92.137924,70.417351 85.649002,70.496323
C76.052444,70.613098 70.883438,75.784592 70.828224,85.278526
C70.791443,91.601952 70.838249,97.925835 70.815323,104.249390
C70.800034,108.465698 69.021706,111.404305 64.542152,111.749588
C60.712017,112.044823 58.149727,108.860695 58.087414,104.008698
C58.025444,99.183578 58.074707,94.357040 58.075195,89.038673
z"/>
<path fill="#1B7AFF" opacity="1.000000" stroke="none"
d="
M89.025162,210.216614
C75.600212,211.119110 65.741669,206.357651 60.193012,194.311264
C58.913387,191.533142 58.307373,188.254333 58.181393,185.173615
C57.889271,178.029922 58.022205,170.865921 58.095528,163.711304
C58.142273,159.150665 60.622017,156.283447 64.323128,156.210587
C68.013466,156.137939 70.688370,158.977814 70.783600,163.526260
C70.922905,170.179581 70.763878,176.838562 70.836990,183.494003
C70.928276,191.804367 76.118484,197.220825 84.428391,197.466827
C90.912674,197.658783 97.408028,197.442291 103.896301,197.544510
C109.409317,197.631393 112.165512,199.956879 112.043839,204.136276
C111.928757,208.089645 109.232590,210.158798 103.996918,210.206680
C99.171547,210.250793 94.345467,210.216370 89.025162,210.216614
z"/>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,93 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="100%" viewBox="0 0 265 265" enable-background="new 0 0 265 265" xml:space="preserve">
<path fill="#F6F7F7" opacity="1.000000" stroke="none"
d="
M177.000000,266.000000
C118.000000,266.000000 59.500000,266.000000 1.000000,266.000000
C1.000000,177.666672 1.000000,89.333336 1.000000,1.000000
C89.333336,1.000000 177.666672,1.000000 266.000000,1.000000
C266.000000,89.333336 266.000000,177.666672 266.000000,266.000000
C236.500000,266.000000 207.000000,266.000000 177.000000,266.000000
M91.845406,197.675049
C92.574387,198.075562 93.289421,198.504288 94.034355,198.872528
C122.143723,212.768463 149.424789,211.358566 174.290878,192.133041
C198.794342,173.187851 207.450577,147.378677 201.018936,117.151642
C194.552002,86.758789 169.407455,64.335747 137.517944,60.563004
C94.225380,55.441200 54.129345,89.053024 55.385788,136.249313
C56.086025,162.552734 68.616104,183.195374 91.845406,197.675049
z"/>
<path fill="#1A79FF" opacity="1.000000" stroke="none"
d="
M91.544540,197.468185
C68.616104,183.195374 56.086025,162.552734 55.385788,136.249313
C54.129345,89.053024 94.225380,55.441200 137.517944,60.563004
C169.407455,64.335747 194.552002,86.758789 201.018936,117.151642
C207.450577,147.378677 198.794342,173.187851 174.290878,192.133041
C149.424789,211.358566 122.143723,212.768463 94.034355,198.872528
C93.289421,198.504288 92.574387,198.075562 91.544540,197.468185
M182.782074,106.853699
C182.376175,106.127602 181.968262,105.402626 181.564697,104.675240
C166.747589,77.969490 133.653259,66.655266 105.699112,78.738861
C77.101509,91.100601 62.547478,122.942497 72.061737,152.332123
C82.730644,185.288498 119.473801,202.554642 151.481689,189.652710
C183.891586,176.588745 198.352127,138.982056 182.782074,106.853699
z"/>
<path fill="#F4F6F7" opacity="1.000000" stroke="none"
d="
M182.916443,107.203209
C198.352127,138.982056 183.891586,176.588745 151.481689,189.652710
C119.473801,202.554642 82.730644,185.288498 72.061737,152.332123
C62.547478,122.942497 77.101509,91.100601 105.699112,78.738861
C133.653259,66.655266 166.747589,77.969490 181.564697,104.675240
C181.968262,105.402626 182.376175,106.127602 182.916443,107.203209
M133.256577,175.119888
C138.038345,173.799881 143.017471,172.951889 147.557480,171.053650
C155.126511,167.888947 161.443085,162.992004 164.039261,154.734512
C164.562103,153.071564 164.508545,150.389999 163.504166,149.319565
C162.497696,148.246918 159.927536,148.206726 158.114822,148.397812
C148.382004,149.423843 138.672394,151.565231 128.953384,151.573013
C119.401138,151.580643 109.818901,149.685349 100.305298,148.255936
C95.093895,147.472916 92.670105,149.398590 94.290924,154.394867
C95.236084,157.308395 96.868782,160.269196 98.953514,162.495911
C107.947685,172.102753 119.322517,175.879929 133.256577,175.119888
M144.358994,124.880630
C148.416534,129.284988 152.583359,130.521561 156.591675,128.180222
C160.345291,125.987686 162.323318,122.698273 161.300598,118.202377
C160.089294,112.877380 155.176727,109.866554 149.979095,111.134056
C144.351532,112.506401 142.042175,117.548599 144.358994,124.880630
M115.050995,121.217003
C114.807083,114.243889 110.802429,110.298233 104.670021,110.988960
C99.538422,111.566956 95.975540,116.358391 96.922661,121.706787
C97.666412,125.906685 100.353622,128.408661 104.550346,129.077759
C109.416664,129.853622 112.505821,127.692970 115.050995,121.217003
z"/>
<path fill="#1979FF" opacity="1.000000" stroke="none"
d="
M132.788025,175.150131
C119.322517,175.879929 107.947685,172.102753 98.953514,162.495911
C96.868782,160.269196 95.236084,157.308395 94.290924,154.394867
C92.670105,149.398590 95.093895,147.472916 100.305298,148.255936
C109.818901,149.685349 119.401138,151.580643 128.953384,151.573013
C138.672394,151.565231 148.382004,149.423843 158.114822,148.397812
C159.927536,148.206726 162.497696,148.246918 163.504166,149.319565
C164.508545,150.389999 164.562103,153.071564 164.039261,154.734512
C161.443085,162.992004 155.126511,167.888947 147.557480,171.053650
C143.017471,172.951889 138.038345,173.799881 132.788025,175.150131
z"/>
<path fill="#1C7AFF" opacity="1.000000" stroke="none"
d="
M144.180573,124.532310
C142.042175,117.548599 144.351532,112.506401 149.979095,111.134056
C155.176727,109.866554 160.089294,112.877380 161.300598,118.202377
C162.323318,122.698273 160.345291,125.987686 156.591675,128.180222
C152.583359,130.521561 148.416534,129.284988 144.180573,124.532310
z"/>
<path fill="#1A79FF" opacity="1.000000" stroke="none"
d="
M115.014488,121.620026
C112.505821,127.692970 109.416664,129.853622 104.550346,129.077759
C100.353622,128.408661 97.666412,125.906685 96.922661,121.706787
C95.975540,116.358391 99.538422,111.566956 104.670021,110.988960
C110.802429,110.298233 114.807083,114.243889 115.014488,121.620026
z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

@ -0,0 +1,74 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="100%" viewBox="0 0 265 265" enable-background="new 0 0 265 265" xml:space="preserve">
<path fill="#F6F7F7" opacity="1.000000" stroke="none"
d="
M126.000000,266.000000
C84.000000,266.000000 42.500000,266.000000 1.000000,266.000000
C1.000000,177.666672 1.000000,89.333336 1.000000,1.000000
C89.333336,1.000000 177.666672,1.000000 266.000000,1.000000
C266.000000,89.333336 266.000000,177.666672 266.000000,266.000000
C219.500000,266.000000 173.000000,266.000000 126.000000,266.000000
M93.271156,108.600227
C95.894211,102.164474 94.953171,97.510170 90.421242,94.504829
C85.899391,91.506187 79.910858,92.457954 75.685272,97.440575
C73.361404,100.180779 71.400116,103.422249 70.036987,106.749718
C64.309616,120.730553 63.700073,135.114838 67.148804,149.786636
C76.013321,187.498581 114.581345,211.752640 151.049347,201.770157
C187.002151,191.928696 208.891022,158.174759 202.311172,118.686409
C197.499985,89.812469 179.805344,70.795700 152.160736,61.197193
C146.918335,59.376972 142.975876,60.777462 141.396835,64.479004
C139.778275,68.273178 141.793015,71.140266 146.873383,74.174019
C152.116379,77.304878 157.604843,80.482285 161.815323,84.784866
C169.490250,92.627663 166.823441,104.243217 156.600845,107.786949
C152.452988,109.224815 147.264969,109.364426 142.975769,108.330139
C134.602890,106.311142 126.565765,102.934784 118.320076,100.341537
C112.300346,98.448349 107.655556,100.165009 105.942001,104.506363
C104.328651,108.593895 106.656288,112.178909 112.347801,115.266685
C118.631081,118.675507 125.275391,121.743057 130.775192,126.182373
C136.489395,130.794739 142.248505,136.171387 145.824692,142.446640
C153.958221,156.718857 143.658936,174.505722 127.303604,175.918686
C108.069801,177.580322 88.004906,161.552246 84.821518,142.458450
C82.760010,130.093597 87.192863,119.603577 93.271156,108.600227
M138.314865,78.415802
C137.164169,78.515045 135.988144,78.495102 134.867050,78.733513
C129.038589,79.972954 125.589058,84.180138 126.291641,89.095604
C127.152306,95.117012 134.282532,100.252167 141.146225,99.793816
C147.024490,99.401268 152.062469,95.318977 151.559097,90.504791
C151.273865,87.776657 149.823227,84.583839 147.831009,82.774704
C145.532578,80.687508 142.059448,79.893906 138.314865,78.415802
z"/>
<path fill="#1878FF" opacity="1.000000" stroke="none"
d="
M93.137238,108.961746
C87.192863,119.603577 82.760010,130.093597 84.821518,142.458450
C88.004906,161.552246 108.069801,177.580322 127.303604,175.918686
C143.658936,174.505722 153.958221,156.718857 145.824692,142.446640
C142.248505,136.171387 136.489395,130.794739 130.775192,126.182373
C125.275391,121.743057 118.631081,118.675507 112.347801,115.266685
C106.656288,112.178909 104.328651,108.593895 105.942001,104.506363
C107.655556,100.165009 112.300346,98.448349 118.320076,100.341537
C126.565765,102.934784 134.602890,106.311142 142.975769,108.330139
C147.264969,109.364426 152.452988,109.224815 156.600845,107.786949
C166.823441,104.243217 169.490250,92.627663 161.815323,84.784866
C157.604843,80.482285 152.116379,77.304878 146.873383,74.174019
C141.793015,71.140266 139.778275,68.273178 141.396835,64.479004
C142.975876,60.777462 146.918335,59.376972 152.160736,61.197193
C179.805344,70.795700 197.499985,89.812469 202.311172,118.686409
C208.891022,158.174759 187.002151,191.928696 151.049347,201.770157
C114.581345,211.752640 76.013321,187.498581 67.148804,149.786636
C63.700073,135.114838 64.309616,120.730553 70.036987,106.749718
C71.400116,103.422249 73.361404,100.180779 75.685272,97.440575
C79.910858,92.457954 85.899391,91.506187 90.421242,94.504829
C94.953171,97.510170 95.894211,102.164474 93.137238,108.961746
z"/>
<path fill="#1C7BFF" opacity="1.000000" stroke="none"
d="
M138.705643,78.477188
C142.059448,79.893906 145.532578,80.687508 147.831009,82.774704
C149.823227,84.583839 151.273865,87.776657 151.559097,90.504791
C152.062469,95.318977 147.024490,99.401268 141.146225,99.793816
C134.282532,100.252167 127.152306,95.117012 126.291641,89.095604
C125.589058,84.180138 129.038589,79.972954 134.867050,78.733513
C135.988144,78.495102 137.164169,78.515045 138.705643,78.477188
z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

832
composer.lock generated
View file

@ -1,832 +0,0 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "524ca69e0ade104f4102231471f256e3",
"packages": [
{
"name": "adbario/php-dot-notation",
"version": "2.5.0",
"source": {
"type": "git",
"url": "https://github.com/adbario/php-dot-notation.git",
"reference": "081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae",
"reference": "081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^5.5 || ^7.0 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8|^5.7|^6.6|^7.5|^8.5|^9.5",
"squizlabs/php_codesniffer": "^3.6"
},
"type": "library",
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Adbar\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Riku Särkinen",
"email": "riku@adbar.io"
}
],
"description": "PHP dot notation access to arrays",
"homepage": "https://github.com/adbario/php-dot-notation",
"keywords": [
"ArrayAccess",
"dotnotation"
],
"support": {
"issues": "https://github.com/adbario/php-dot-notation/issues",
"source": "https://github.com/adbario/php-dot-notation/tree/2.5.0"
},
"time": "2022-10-14T20:31:46+00:00"
},
{
"name": "alibabacloud/tea",
"version": "3.2.1",
"source": {
"type": "git",
"url": "https://github.com/aliyun/tea-php.git",
"reference": "1619cb96c158384f72b873e1f85de8b299c9c367"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aliyun/tea-php/zipball/1619cb96c158384f72b873e1f85de8b299c9c367",
"reference": "1619cb96c158384f72b873e1f85de8b299c9c367",
"shasum": ""
},
"require": {
"adbario/php-dot-notation": "^2.4",
"ext-curl": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-simplexml": "*",
"ext-xmlwriter": "*",
"guzzlehttp/guzzle": "^6.3|^7.0",
"php": ">=5.5"
},
"require-dev": {
"phpunit/phpunit": "*",
"symfony/dotenv": "^3.4",
"symfony/var-dumper": "^3.4"
},
"suggest": {
"ext-sockets": "To use client-side monitoring"
},
"type": "library",
"autoload": {
"psr-4": {
"AlibabaCloud\\Tea\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Alibaba Cloud SDK",
"email": "sdk-team@alibabacloud.com",
"homepage": "http://www.alibabacloud.com"
}
],
"description": "Client of Tea for PHP",
"homepage": "https://www.alibabacloud.com/",
"keywords": [
"alibabacloud",
"client",
"cloud",
"tea"
],
"support": {
"issues": "https://github.com/aliyun/tea-php/issues",
"source": "https://github.com/aliyun/tea-php"
},
"time": "2023-05-16T06:43:41+00:00"
},
{
"name": "alibabacloud/tea-fileform",
"version": "0.3.4",
"source": {
"type": "git",
"url": "https://github.com/alibabacloud-sdk-php/tea-fileform.git",
"reference": "4bf0c75a045c8115aa8cb1a394bd08d8bb833181"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alibabacloud-sdk-php/tea-fileform/zipball/4bf0c75a045c8115aa8cb1a394bd08d8bb833181",
"reference": "4bf0c75a045c8115aa8cb1a394bd08d8bb833181",
"shasum": ""
},
"require": {
"alibabacloud/tea": "^3.0",
"php": ">5.5"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5.4.3"
},
"type": "library",
"autoload": {
"psr-4": {
"AlibabaCloud\\Tea\\FileForm\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Alibaba Cloud SDK",
"email": "sdk-team@alibabacloud.com"
}
],
"description": "Alibaba Cloud Tea File Library for PHP",
"support": {
"issues": "https://github.com/alibabacloud-sdk-php/tea-fileform/issues",
"source": "https://github.com/alibabacloud-sdk-php/tea-fileform/tree/0.3.4"
},
"time": "2020-12-01T07:24:35+00:00"
},
{
"name": "alipaysdk/easysdk",
"version": "2.2.3",
"source": {
"type": "git",
"url": "https://github.com/alipay/alipay-easysdk.git",
"reference": "c6008839a22a5fca08e9f8536730f7abfed522d5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alipay/alipay-easysdk/zipball/c6008839a22a5fca08e9f8536730f7abfed522d5",
"reference": "c6008839a22a5fca08e9f8536730f7abfed522d5",
"shasum": ""
},
"require": {
"alibabacloud/tea": "^3.1",
"alibabacloud/tea-fileform": "^0.3.2",
"ext-ctype": "*",
"ext-curl": "*",
"ext-dom": "*",
"ext-fileinfo": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-simplexml": "*",
"ext-xmlwriter": "*",
"guzzlehttp/guzzle": ">=6.3",
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Alipay\\EasySDK\\": "php/src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "junying.wjy",
"email": "junying.wjy@antfin.com"
}
],
"description": "支付宝官方 Alipay Easy SDK",
"support": {
"source": "https://github.com/alipay/alipay-easysdk/tree/v2.2.3"
},
"time": "2022-11-28T14:04:57+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "7.10.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^2.3",
"guzzlehttp/psr7": "^2.8",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
"provide": {
"psr/http-client-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*",
"guzzle/client-integration-tests": "3.0.2",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.39 || ^9.6.20",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
"ext-curl": "Required for CURL handler support",
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Jeremy Lindblom",
"email": "jeremeamia@gmail.com",
"homepage": "https://github.com/jeremeamia"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle is a PHP HTTP client library",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"psr-18",
"psr-7",
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.10.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
"type": "tidelift"
}
],
"time": "2025-08-23T22:36:01+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "481557b130ef3790cf82b713667b43030dc9c957"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
"reference": "481557b130ef3790cf82b713667b43030dc9c957",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.3.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
"type": "tidelift"
}
],
"time": "2025-08-22T14:34:08+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "21dc724a0583619cd1652f673303492272778051"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
"reference": "21dc724a0583619cd1652f673303492272778051",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.1 || ^2.0",
"ralouphie/getallheaders": "^3.0"
},
"provide": {
"psr/http-factory-implementation": "1.0",
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "0.9.0",
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://sagikazarmark.hu"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
"psr-7",
"request",
"response",
"stream",
"uri",
"url"
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.8.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
"type": "tidelift"
}
],
"time": "2025-08-23T21:21:41+00:00"
},
{
"name": "psr/http-client",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
"homepage": "https://github.com/php-fig/http-client",
"keywords": [
"http",
"http-client",
"psr",
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client"
},
"time": "2023-09-23T14:17:50+00:00"
},
{
"name": "psr/http-factory",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"shasum": ""
},
"require": {
"php": ">=7.1",
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
"message",
"psr",
"psr-17",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory"
},
"time": "2024-04-15T12:06:14+00:00"
},
{
"name": "psr/http-message",
"version": "2.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/2.0"
},
"time": "2023-04-04T09:54:51+00:00"
},
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/ralouphie/getallheaders.git",
"reference": "120b605dfeb996808c31b6477290a714d356e822"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
"reference": "120b605dfeb996808c31b6477290a714d356e822",
"shasum": ""
},
"require": {
"php": ">=5.6"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^5 || ^6.5"
},
"type": "library",
"autoload": {
"files": [
"src/getallheaders.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ralph Khattar",
"email": "ralph.khattar@gmail.com"
}
],
"description": "A polyfill for getallheaders.",
"support": {
"issues": "https://github.com/ralouphie/getallheaders/issues",
"source": "https://github.com/ralouphie/getallheaders/tree/develop"
},
"time": "2019-03-08T08:55:37+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-25T14:21:43+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View file

@ -1,201 +0,0 @@
/**
* 当面付支付样式
*/

.alipay-qrcode-container {
max-width: 500px;
margin: 30px auto;
padding: 30px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
text-align: center;
}

.alipay-qrcode-header {
margin-bottom: 20px;
}

.alipay-qrcode-header h2 {
margin: 0 0 10px 0;
font-size: 24px;
color: #333;
}

.alipay-qrcode-header .order-info {
font-size: 16px;
color: #666;
}

.alipay-qrcode-header .order-amount {
font-size: 32px;
font-weight: 700;
color: #1677ff;
margin: 15px 0;
}

.alipay-qrcode-wrapper {
margin: 20px 0;
padding: 20px;
background: #f9f9f9;
border-radius: 8px;
display: inline-block;
}

#alipay-qrcode {
display: flex;
justify-content: center;
align-items: center;
}

#alipay-qrcode canvas,
#alipay-qrcode img {
max-width: 100%;
height: auto;
border: 8px solid #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
border-radius: 4px;
}

.alipay-qrcode-tips {
margin-top: 20px;
padding: 15px;
background: #f0f7ff;
border: 1px solid #d6e4ff;
border-radius: 4px;
color: #096dd9;
}

.alipay-qrcode-tips p {
margin: 8px 0;
font-size: 14px;
line-height: 1.6;
}

.alipay-qrcode-tips .tip-icon {
display: inline-block;
margin-right: 5px;
font-weight: bold;
}

.alipay-payment-status {
margin-top: 20px;
padding: 15px;
background: #fff9e6;
border: 1px solid #ffd666;
border-radius: 4px;
}

.alipay-payment-status.success {
background: #f6ffed;
border-color: #b7eb8f;
color: #52c41a;
}

.alipay-payment-status.error {
background: #fff1f0;
border-color: #ffa39e;
color: #ff4d4f;
}

.alipay-payment-status .status-icon {
display: inline-block;
margin-right: 8px;
font-size: 18px;
}

.alipay-payment-status .status-text {
font-size: 15px;
font-weight: 500;
}

.alipay-qrcode-loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 300px;
}

.alipay-qrcode-loading .spinner {
width: 50px;
height: 50px;
border: 4px solid #f0f0f0;
border-top: 4px solid #1677ff;
border-radius: 50%;
animation: spin 1s linear infinite;
}

@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

.alipay-qrcode-loading .loading-text {
margin-top: 15px;
font-size: 14px;
color: #666;
}

.alipay-qrcode-expired {
padding: 30px;
text-align: center;
}

.alipay-qrcode-expired .expired-icon {
font-size: 48px;
color: #ff4d4f;
margin-bottom: 15px;
}

.alipay-qrcode-expired .expired-text {
font-size: 16px;
color: #666;
margin-bottom: 20px;
}

.alipay-qrcode-expired .refresh-button {
padding: 10px 30px;
background: #1677ff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 15px;
transition: background 0.3s;
}

.alipay-qrcode-expired .refresh-button:hover {
background: #4096ff;
}

.alipay-qrcode-timer {
margin-top: 15px;
font-size: 14px;
color: #999;
}

.alipay-qrcode-timer.warning {
color: #ff4d4f;
font-weight: 600;
}

/* 移动端适配 */
@media (max-width: 768px) {
.alipay-qrcode-container {
margin: 15px;
padding: 20px;
}
.alipay-qrcode-header h2 {
font-size: 20px;
}
.alipay-qrcode-header .order-amount {
font-size: 28px;
}
.alipay-qrcode-wrapper {
padding: 15px;
}
}

View file

@ -1,120 +0,0 @@
/**
* 花呗分期支付样式
*/

.alipay-installment-selector {
margin: 15px 0;
padding: 15px;
background: #f9f9f9;
border: 1px solid #e0e0e0;
border-radius: 4px;
}

.alipay-installment-selector p {
margin: 0 0 10px 0;
font-weight: 600;
color: #333;
}

.installment-periods {
list-style: none;
margin: 0;
padding: 0;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 10px;
}

.installment-periods li {
margin: 0;
padding: 0;
}

.installment-periods label {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 15px;
background: #fff;
border: 2px solid #ddd;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s ease;
}

.installment-periods label:hover {
border-color: #1677ff;
background: #f0f7ff;
}

.installment-periods input[type="radio"] {
margin-right: 10px;
width: 18px;
height: 18px;
}

.installment-periods input[type="radio"]:checked + .period-label {
color: #1677ff;
font-weight: 600;
}

.installment-periods label:has(input:checked) {
border-color: #1677ff;
background: #f0f7ff;
box-shadow: 0 0 0 1px #1677ff;
}

.period-label {
flex: 1;
font-size: 15px;
font-weight: 500;
color: #333;
}

.period-amount {
font-size: 14px;
color: #666;
font-weight: 500;
}

.alipay-installment-notice {
padding: 10px 15px;
background: #fff3cd;
border: 1px solid #ffc107;
border-radius: 4px;
color: #856404;
margin: 10px 0;
}

.alipay-badge {
display: inline-block;
padding: 0 6px;
line-height: 18px;
height: 18px;
border-radius: 9px;
font-size: 12px;
font-weight: 600;
margin-left: 6px;
}

.alipay-badge--free {
background: #e8f5e9;
color: #2e7d32;
border: 1px solid #a5d6a7;
}

/* 移动端适配 */
@media (max-width: 768px) {
.installment-periods {
grid-template-columns: 1fr;
}
.installment-periods label {
padding: 10px 12px;
}
.period-label,
.period-amount {
font-size: 14px;
}
}

30
enable-gateways.php Normal file
View file

@ -0,0 +1,30 @@
<?php
/**
* 一键启用所有支付网关
*
* 访问: yoursite.com/?enable_alipay_gateways=1
* 必须以管理员身份登录
*/

if ( ! defined( 'ABSPATH' ) ) {
exit;
}

add_action( 'init', function() {
if ( ! isset( $_GET['enable_alipay_gateways'] ) || ! current_user_can( 'manage_woocommerce' ) ) {
return;
}
$gateways = ['alipay', 'alipay_installment', 'alipay_facetopay'];
foreach ( $gateways as $gateway_id ) {
$option_key = 'woocommerce_' . $gateway_id . '_settings';
$settings = get_option( $option_key, [] );
$settings['enabled'] = 'yes';
update_option( $option_key, $settings );
}
wp_cache_flush();
wp_die( '<h1>✓ 完成!</h1><p>所有支付网关已启用。</p><p><a href="' . admin_url( 'admin.php?page=wc-settings&tab=checkout' ) . '">查看支付设置</a></p>' );
}, 1 );

View file

@ -0,0 +1,140 @@
<?php
if ( ! defined( 'ABSPATH' ) ) { exit; }

class WC_Alipay_Agreement {
const META_USER_AGREEMENT_NO = '_alipay_agreement_no';
const META_USER_AGREEMENT_STATUS = '_alipay_agreement_status';
const META_USER_PENDING_EXTERNAL_SIGN_NO = '_alipay_pending_external_sign_no';

public static function init() {
add_action( 'init', [ __CLASS__, 'register_api_endpoints' ] );
}

public static function register_api_endpoints() {
add_action( 'woocommerce_api_wc_alipay_agreement_notify', [ __CLASS__, 'handle_agreement_notify' ] );
add_action( 'woocommerce_api_wc_alipay_agreement_return', [ __CLASS__, 'handle_agreement_return' ] );
add_action( 'woocommerce_api_wc_alipay_agreement_start', [ __CLASS__, 'handle_agreement_start' ] );
}

public static function get_sign_url( $user_id = 0, $context = [] ) {
$gateway = new WC_Alipay( false );
$notify_url = add_query_arg( [], WC()->api_request_url( 'WC_Alipay_Agreement_Notify' ) );
$return_url = add_query_arg( [], WC()->api_request_url( 'WC_Alipay_Agreement_Return' ) );

require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/AopClient.php';
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/request/AlipayUserAgreementPageSignRequest.php';

$aop = new AopClient();
$aop->gatewayUrl = ( 'yes' === $gateway->get_option( 'sandbox' ) ) ? WC_Alipay::GATEWAY_SANDBOX_URL : WC_Alipay::GATEWAY_URL;
$aop->appId = $gateway->get_option( 'appid' );
$aop->rsaPrivateKey = $gateway->get_option( 'private_key' );
$aop->alipayrsaPublicKey= $gateway->get_option( 'public_key' );
$aop->charset = 'utf-8';
$aop->signType = 'RSA2';

$external_sign_no = 'AGREE' . ( $user_id ? $user_id : get_current_user_id() ) . '-' . current_time( 'timestamp' );
// 建立 external_sign_no 到用户的临时映射
if ( $user_id ) {
set_transient( 'woo_alipay_pending_user_' . $external_sign_no, absint( $user_id ), DAY_IN_SECONDS );
update_user_meta( $user_id, self::META_USER_PENDING_EXTERNAL_SIGN_NO, $external_sign_no );
}

$personal_product_code = apply_filters( 'woo_alipay_agreement_personal_product_code', 'CYCLE_PAY_AUTH', $user_id );
$sign_scene = apply_filters( 'woo_alipay_agreement_sign_scene', 'INDUSTRY|DEFAULT', $user_id );

$biz = [
'external_sign_no' => $external_sign_no,
'personal_product_code' => $personal_product_code,
'sign_scene' => $sign_scene,
'access_params' => [ 'channel' => 'ALIPAYAPP' ],
'merchant_process_url' => $return_url,
'notify_url' => $notify_url,
];
if ( ! empty( $context['return_url'] ) ) {
$biz['merchant_process_url'] = $context['return_url'];
}

$request = new AlipayUserAgreementPageSignRequest();
$request->setBizContent( wp_json_encode( $biz ) );
$request->setNotifyUrl( $notify_url );
$request->setReturnUrl( $return_url );

// pageExecute 返回跳转 URL/表单
$sign_form_or_url = $aop->pageExecute( $request );
return [ 'payload' => $sign_form_or_url, 'external_sign_no' => $external_sign_no ];
}

public static function handle_agreement_return() {
// 用户浏览器跳转回站点,可用于展示成功页面;协议最终以异步通知为准
wp_safe_redirect( home_url() );
exit;
}

public static function handle_agreement_notify() {
$gateway = new WC_Alipay( false );
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/AopClient.php';
$aop = new AopClient();
$aop->alipayrsaPublicKey= $gateway->get_option( 'public_key' );
$aop->charset = 'utf-8';
$aop->signType = 'RSA2';

$params = wp_unslash( $_POST );
$verified = $aop->rsaCheckV1( $params, $aop->alipayrsaPublicKey, $aop->signType );
if ( ! $verified ) {
echo 'fail';
exit;
}

$agreement_no = isset( $params['agreement_no'] ) ? sanitize_text_field( $params['agreement_no'] ) : '';
$alipay_user_id = isset( $params['alipay_user_id'] ) ? sanitize_text_field( $params['alipay_user_id'] ) : '';
$status = isset( $params['status'] ) ? sanitize_text_field( $params['status'] ) : '';
$external_sign_no = isset( $params['external_sign_no'] ) ? sanitize_text_field( $params['external_sign_no'] ) : '';

// 根据 external_sign_no 还原用户
$user_id = 0;
if ( $external_sign_no ) {
$user_id = absint( get_transient( 'woo_alipay_pending_user_' . $external_sign_no ) );
}
if ( ! $user_id && is_user_logged_in() ) {
$user_id = get_current_user_id();
}
if ( $user_id ) {
update_user_meta( $user_id, self::META_USER_AGREEMENT_NO, $agreement_no );
update_user_meta( $user_id, self::META_USER_AGREEMENT_STATUS, $status );
delete_transient( 'woo_alipay_pending_user_' . $external_sign_no );
delete_user_meta( $user_id, self::META_USER_PENDING_EXTERNAL_SIGN_NO );
}

echo 'success';
exit;
}

public static function get_user_agreement_no( $user_id ) {
return get_user_meta( $user_id, self::META_USER_AGREEMENT_NO, true );
}

public static function has_user_agreement( $user_id ) {
return (bool) self::get_user_agreement_no( $user_id );
}

public static function handle_agreement_start() {
if ( ! is_user_logged_in() ) {
wp_die( __( '请先登录后再进行签约授权。', 'woo-alipay' ) );
}
$user_id = get_current_user_id();
$context = [];
if ( isset( $_GET['return_url'] ) ) {
$context['return_url'] = esc_url_raw( wp_unslash( $_GET['return_url'] ) );
}
$result = self::get_sign_url( $user_id, $context );
if ( is_array( $result ) && ! empty( $result['payload'] ) ) {
// 输出表单/HTML通常将自动跳转到支付宝
echo $result['payload'];
exit;
}
wp_die( __( '无法生成签约请求,请稍后重试。', 'woo-alipay' ) );
}

}

WC_Alipay_Agreement::init();

View file

@ -1,71 +0,0 @@
<?php

use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;

/**
* 当面付支付的 WooCommerce Blocks 支持类
*/
final class WC_Alipay_FaceToPay_Blocks_Support extends AbstractPaymentMethodType {

private $gateway;
protected $name = 'alipay_facetopay';

public function __construct() {
$this->name = 'alipay_facetopay';
}

public function initialize() {
$this->settings = get_option( 'woocommerce_alipay_facetopay_settings', array() );
$gateways = WC()->payment_gateways->payment_gateways();
$this->gateway = isset( $gateways['alipay_facetopay'] ) ? $gateways['alipay_facetopay'] : false;
}

public function is_active() {
$enabled = isset( $this->settings['enabled'] ) ? $this->settings['enabled'] : 'no';
return 'yes' === $enabled;
}

public function get_payment_method_script_handles() {
$script_path = 'js/frontend/blocks-facetopay.js';
$script_asset_path = WOO_ALIPAY_PLUGIN_PATH . 'js/frontend/blocks-facetopay.asset.php';
$script_asset = file_exists( $script_asset_path )
? require( $script_asset_path )
: array(
'dependencies' => array( 'wc-blocks-registry', 'wp-element', 'wp-html-entities', 'wp-i18n' ),
'version' => WOO_ALIPAY_VERSION
);
$script_url = trailingslashit( WOO_ALIPAY_PLUGIN_URL ) . $script_path;

wp_register_script(
'wc-alipay-facetopay-payments-blocks',
$script_url,
$script_asset['dependencies'],
$script_asset['version'],
true
);

if ( function_exists( 'wp_set_script_translations' ) ) {
wp_set_script_translations( 'wc-alipay-facetopay-payments-blocks', 'woo-alipay', WOO_ALIPAY_PLUGIN_PATH . 'languages' );
}

return [ 'wc-alipay-facetopay-payments-blocks' ];
}

public function get_payment_method_script_handles_for_admin() {
return $this->get_payment_method_script_handles();
}

public function get_payment_method_data() {
return [
'title' => $this->get_setting( 'title', '支付宝扫码支付' ),
'description' => $this->get_setting( 'description', '使用支付宝扫描二维码完成支付' ),
'supports' => $this->get_supported_features(),
'icon' => WOO_ALIPAY_PLUGIN_URL . 'assets/images/alipay-icon.svg',
];
}

public function get_supported_features() {
return $this->gateway ? $this->gateway->supports : ['products'];
}
}

View file

@ -1,568 +0,0 @@
<?php
if (!defined('ABSPATH')) {
exit;
}

/**
* 支付宝当面付支付网关
*
* 支持扫码支付功能,商家展示二维码供用户扫描支付
* 适用于收银台、实体店等线下场景
*/
class WC_Alipay_FaceToPay extends WC_Payment_Gateway
{
const GATEWAY_ID = 'alipay_facetopay';
protected static $log_enabled = false;
protected static $log = false;
protected $current_currency;
protected $exchange_rate;
protected $order_prefix;
protected $notify_url;
protected $charset;

public function __construct()
{
$this->id = self::GATEWAY_ID;
$this->method_title = __('支付宝当面付', 'woo-alipay');
$this->method_description = __('支持当面付扫码支付,商家展示二维码供用户扫描。适用于收银台、实体店等场景。需要在支付宝商户后台开通当面付功能。', 'woo-alipay');
$this->icon = WOO_ALIPAY_PLUGIN_URL . 'assets/images/alipay-icon.svg';
$this->has_fields = false;
$this->charset = strtolower(get_bloginfo('charset'));
if (!in_array($this->charset, array('gbk', 'utf-8'), true)) {
$this->charset = 'utf-8';
}
$this->init_form_fields();
$this->init_settings();
$this->title = $this->get_option('title', __('支付宝扫码支付', 'woo-alipay'));
$this->description = $this->get_option('description');
$this->enabled = $this->get_option('enabled');
$this->current_currency = get_option('woocommerce_currency');
$this->exchange_rate = $this->get_option('exchange_rate');
$this->order_prefix = $this->get_option('order_prefix', 'F2F');
$this->notify_url = WC()->api_request_url('WC_Alipay_FaceToPay');
self::$log_enabled = ('yes' === $this->get_option('debug', 'no'));
$this->supports = array(
'products',
'refunds',
);
add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options'));
add_action('woocommerce_receipt_' . $this->id, array($this, 'receipt_page'));
add_action('woocommerce_api_wc_alipay_facetopay', array($this, 'check_alipay_response'));
add_action('wp_ajax_alipay_facetopay_query', array($this, 'ajax_query_payment_status'));
add_action('wp_ajax_nopriv_alipay_facetopay_query', array($this, 'ajax_query_payment_status'));
add_action('wp_ajax_alipay_facetopay_refresh_qrcode', array($this, 'ajax_refresh_qrcode'));
add_action('wp_ajax_nopriv_alipay_facetopay_refresh_qrcode', array($this, 'ajax_refresh_qrcode'));
add_action('wp_enqueue_scripts', array($this, 'payment_scripts'));
}

public function init_form_fields()
{
$this->form_fields = array(
'enabled' => array(
'title' => __('启用/禁用', 'woo-alipay'),
'type' => 'checkbox',
'label' => __('启用支付宝当面付', 'woo-alipay'),
'default' => 'no',
),
'title' => array(
'title' => __('标题', 'woo-alipay'),
'type' => 'text',
'description' => __('用户在结账时看到的支付方式名称', 'woo-alipay'),
'default' => __('支付宝扫码支付', 'woo-alipay'),
'desc_tip' => true,
),
'description' => array(
'title' => __('描述', 'woo-alipay'),
'type' => 'textarea',
'description' => __('支付方式描述', 'woo-alipay'),
'default' => __('使用支付宝扫描二维码完成支付', 'woo-alipay'),
'desc_tip' => true,
),
'qrcode_settings' => array(
'title' => __('二维码设置', 'woo-alipay'),
'type' => 'title',
),
'qrcode_size' => array(
'title' => __('二维码尺寸', 'woo-alipay'),
'type' => 'number',
'description' => __('二维码显示尺寸(像素)', 'woo-alipay'),
'default' => '300',
'desc_tip' => true,
'custom_attributes' => array(
'min' => '100',
'max' => '500',
'step' => '10',
),
),
'qrcode_timeout' => array(
'title' => __('二维码有效期', 'woo-alipay'),
'type' => 'select',
'description' => __('二维码的有效时间', 'woo-alipay'),
'default' => '120',
'options' => array(
'60' => __('1分钟', 'woo-alipay'),
'120' => __('2分钟', 'woo-alipay'),
'180' => __('3分钟', 'woo-alipay'),
'300' => __('5分钟', 'woo-alipay'),
'600' => __('10分钟', 'woo-alipay'),
),
'desc_tip' => true,
),
'polling_settings' => array(
'title' => __('轮询设置', 'woo-alipay'),
'type' => 'title',
),
'polling_interval' => array(
'title' => __('轮询间隔', 'woo-alipay'),
'type' => 'number',
'description' => __('查询支付状态的间隔时间(秒)', 'woo-alipay'),
'default' => '2',
'desc_tip' => true,
'custom_attributes' => array(
'min' => '1',
'max' => '10',
'step' => '1',
),
),
'order_prefix' => array(
'title' => __('订单号前缀', 'woo-alipay'),
'type' => 'text',
'description' => __('当面付订单号的前缀', 'woo-alipay'),
'default' => 'F2F',
'desc_tip' => true,
),
'debug' => array(
'title' => __('调试日志', 'woo-alipay'),
'type' => 'checkbox',
'label' => __('启用日志记录', 'woo-alipay'),
'default' => 'no',
'description' => sprintf(
__('记录当面付相关日志到 %s', 'woo-alipay'),
'<code>' . WC_Log_Handler_File::get_log_file_path($this->id) . '</code>'
),
),
);
if (!in_array($this->current_currency, array('CNY', 'RMB'), true)) {
$this->form_fields['exchange_rate'] = array(
'title' => __('汇率', 'woo-alipay'),
'type' => 'number',
'description' => sprintf(
__('设置 %s 与人民币的汇率', 'woo-alipay'),
$this->current_currency
),
'default' => '7.0',
'desc_tip' => true,
'custom_attributes' => array(
'step' => '0.01',
'min' => '0.01',
),
);
}
}

public function payment_scripts()
{
if (!is_checkout() && !is_order_received_page()) {
return;
}
wp_enqueue_style(
'alipay-facetopay',
WOO_ALIPAY_PLUGIN_URL . 'css/alipay-facetopay.css',
array(),
WOO_ALIPAY_VERSION
);
wp_enqueue_script(
'qrcodejs',
'https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js',
array(),
'1.0.0',
true
);
wp_enqueue_script(
'alipay-facetopay',
WOO_ALIPAY_PLUGIN_URL . 'js/alipay-facetopay.js',
array('jquery', 'qrcodejs'),
WOO_ALIPAY_VERSION,
true
);
wp_localize_script('alipay-facetopay', 'alipayFaceToPayParams', array(
'ajax_url' => admin_url('admin-ajax.php'),
'polling_interval' => intval($this->get_option('polling_interval', 2)) * 1000,
'timeout' => intval($this->get_option('qrcode_timeout', 120)),
));
}

public function process_payment($order_id)
{
$order = wc_get_order($order_id);
$order->update_status('pending', __('等待扫码支付', 'woo-alipay'));
WC()->cart->empty_cart();
return array(
'result' => 'success',
'redirect' => $order->get_checkout_payment_url(true),
);
}

public function receipt_page($order_id)
{
$order = wc_get_order($order_id);
if (!$order || $order->is_paid()) {
return;
}
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-alipay-sdk-helper.php';
$main_gateway = new WC_Alipay(false);
$config = Alipay_SDK_Helper::get_alipay_config(array(
'appid' => $main_gateway->get_option('appid'),
'private_key' => $main_gateway->get_option('private_key'),
'public_key' => $main_gateway->get_option('public_key'),
'sandbox' => $main_gateway->get_option('sandbox'),
));
$aop = Alipay_SDK_Helper::create_alipay_service($config);
if (!$aop) {
wc_add_notice(__('支付初始化失败', 'woo-alipay'), 'error');
return;
}
$total = $this->convert_to_rmb($order->get_total());
$out_trade_no = Alipay_SDK_Helper::generate_out_trade_no($order_id, $this->order_prefix);
$order->update_meta_data('_alipay_out_trade_no', $out_trade_no);
$order->save();
try {
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/request/AlipayTradePrecreateRequest.php';
$request = new AlipayTradePrecreateRequest();
$biz_content = array(
'out_trade_no' => $out_trade_no,
'total_amount' => Alipay_SDK_Helper::format_amount($total),
'subject' => $this->get_order_title($order),
'body' => $this->get_order_description($order),
'timeout_express' => $this->get_option('qrcode_timeout', 120) . 's',
);
$request->setBizContent(json_encode($biz_content));
$request->setNotifyUrl($this->notify_url);
$response = $aop->execute($request);
$response_node = 'alipay_trade_precreate_response';
$result = $response->$response_node;
if (isset($result->code) && $result->code === '10000') {
$qr_code = $result->qr_code;
$order->update_meta_data('_alipay_qrcode', $qr_code);
$order->save();
self::log('当面付二维码生成成功: ' . $out_trade_no);
$this->display_qrcode_page($order, $qr_code);
} else {
self::log('当面付二维码生成失败: ' . ($result->sub_msg ?? $result->msg), 'error');
wc_add_notice(__('生成支付二维码失败', 'woo-alipay'), 'error');
}
} catch (Exception $e) {
self::log('当面付异常: ' . $e->getMessage(), 'error');
wc_add_notice(__('支付请求失败', 'woo-alipay'), 'error');
}
}

protected function display_qrcode_page($order, $qr_code)
{
$qrcode_size = intval($this->get_option('qrcode_size', 300));
$timeout = intval($this->get_option('qrcode_timeout', 120));
include WOO_ALIPAY_PLUGIN_PATH . 'inc/templates/payment-qrcode.php';
}

public function ajax_refresh_qrcode()
{
check_ajax_referer('alipay_facetopay_query', 'nonce');
$order_id = intval($_POST['order_id'] ?? 0);
if (!$order_id) {
wp_send_json_error(array('message' => 'Invalid order ID'));
}
$order = wc_get_order($order_id);
if (!$order || $order->is_paid()) {
wp_send_json_error(array('message' => 'Invalid order'));
}
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-alipay-sdk-helper.php';
$main_gateway = new WC_Alipay(false);
$config = Alipay_SDK_Helper::get_alipay_config(array(
'appid' => $main_gateway->get_option('appid'),
'private_key' => $main_gateway->get_option('private_key'),
'public_key' => $main_gateway->get_option('public_key'),
'sandbox' => $main_gateway->get_option('sandbox'),
));
try {
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/request/AlipayTradePrecreateRequest.php';
$aop = Alipay_SDK_Helper::create_alipay_service($config);
if (!$aop) {
wp_send_json_error(array('message' => 'SDK init failed'));
}
$out_trade_no = Alipay_SDK_Helper::generate_out_trade_no($order_id, $this->order_prefix);
$order->update_meta_data('_alipay_out_trade_no', $out_trade_no);
$order->save();
$request = new AlipayTradePrecreateRequest();
$biz_content = array(
'out_trade_no' => $out_trade_no,
'total_amount' => Alipay_SDK_Helper::format_amount($this->convert_to_rmb($order->get_total())),
'subject' => $this->get_order_title($order),
'body' => $this->get_order_description($order),
'timeout_express' => $this->get_option('qrcode_timeout', 120) . 's',
);
$request->setBizContent(json_encode($biz_content));
$request->setNotifyUrl($this->notify_url);
$response = $aop->execute($request);
$response_node = 'alipay_trade_precreate_response';
$result = $response->$response_node;
if (isset($result->code) && $result->code === '10000') {
$qr_code = $result->qr_code;
$order->update_meta_data('_alipay_qrcode', $qr_code);
$order->save();
wp_send_json_success(array(
'qr_code' => $qr_code,
'timeout' => intval($this->get_option('qrcode_timeout', 120))
));
}
wp_send_json_error(array('message' => 'Precreate failed'));
} catch (Exception $e) {
wp_send_json_error(array('message' => $e->getMessage()));
}
}

public function ajax_query_payment_status()
{
check_ajax_referer('alipay_facetopay_query', 'nonce');
$order_id = intval($_POST['order_id'] ?? 0);
if (!$order_id) {
wp_send_json_error(array('message' => 'Invalid order ID'));
}
$order = wc_get_order($order_id);
if (!$order) {
wp_send_json_error(array('message' => 'Order not found'));
}
if ($order->is_paid()) {
wp_send_json_success(array(
'status' => 'paid',
'redirect_url' => $order->get_checkout_order_received_url(),
));
}
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-alipay-sdk-helper.php';
$main_gateway = new WC_Alipay(false);
$config = Alipay_SDK_Helper::get_alipay_config(array(
'appid' => $main_gateway->get_option('appid'),
'private_key' => $main_gateway->get_option('private_key'),
'public_key' => $main_gateway->get_option('public_key'),
'sandbox' => $main_gateway->get_option('sandbox'),
));
$out_trade_no = $order->get_meta('_alipay_out_trade_no');
$result = Alipay_SDK_Helper::query_order($out_trade_no, '', $config);
if (!is_wp_error($result) && $result['success']) {
if (in_array($result['trade_status'], array('TRADE_SUCCESS', 'TRADE_FINISHED'), true)) {
if (!$order->is_paid()) {
$order->payment_complete($result['trade_no']);
$order->add_order_note(
sprintf(__('当面付支付完成 - 交易号: %s', 'woo-alipay'), $result['trade_no'])
);
}
wp_send_json_success(array(
'status' => 'paid',
'redirect_url' => $order->get_checkout_order_received_url(),
));
}
}
wp_send_json_success(array('status' => 'pending'));
}

public function check_alipay_response()
{
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-alipay-sdk-helper.php';
$main_gateway = new WC_Alipay(false);
$alipay_public_key = $main_gateway->get_option('public_key');
if (!Alipay_SDK_Helper::verify_notify($_POST, $alipay_public_key)) {
self::log('当面付通知签名验证失败', 'error');
echo 'fail';
exit;
}
$out_trade_no = $_POST['out_trade_no'] ?? '';
$trade_no = $_POST['trade_no'] ?? '';
$trade_status = $_POST['trade_status'] ?? '';
self::log('当面付支付通知: ' . print_r($_POST, true));
$orders = wc_get_orders(array(
'meta_key' => '_alipay_out_trade_no',
'meta_value' => $out_trade_no,
'limit' => 1,
));
if (empty($orders)) {
self::log('未找到订单: ' . $out_trade_no, 'error');
echo 'fail';
exit;
}
$order = $orders[0];
if ($trade_status === 'TRADE_SUCCESS' || $trade_status === 'TRADE_FINISHED') {
if (!$order->is_paid()) {
$order->payment_complete($trade_no);
$order->add_order_note(
sprintf(__('当面付支付完成 - 交易号: %s', 'woo-alipay'), $trade_no)
);
}
echo 'success';
} else {
echo 'fail';
}
exit;
}

public function process_refund($order_id, $amount = null, $reason = '')
{
$order = wc_get_order($order_id);
if (!$order) {
return new WP_Error('error', __('订单不存在', 'woo-alipay'));
}
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-alipay-sdk-helper.php';
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/AopClient.php';
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/request/AlipayTradeRefundRequest.php';
$main_gateway = new WC_Alipay(false);
$config = Alipay_SDK_Helper::get_alipay_config(array(
'appid' => $main_gateway->get_option('appid'),
'private_key' => $main_gateway->get_option('private_key'),
'public_key' => $main_gateway->get_option('public_key'),
'sandbox' => $main_gateway->get_option('sandbox'),
));
$aop = Alipay_SDK_Helper::create_alipay_service($config);
if (!$aop) {
return new WP_Error('sdk_error', __('创建支付宝服务失败', 'woo-alipay'));
}
$out_trade_no = $order->get_meta('_alipay_out_trade_no');
if (!$out_trade_no) {
$out_trade_no = Alipay_SDK_Helper::generate_out_trade_no($order_id, $this->order_prefix);
}
$refund_amount = $amount ? floatval($amount) : floatval($order->get_total());
$refund_reason = $reason ? $reason : __('订单退款', 'woo-alipay');
try {
$request = new AlipayTradeRefundRequest();
$biz_content = array(
'out_trade_no' => $out_trade_no,
'refund_amount' => Alipay_SDK_Helper::format_amount($refund_amount),
'refund_reason' => $refund_reason,
);
$request->setBizContent(json_encode($biz_content));
$response = $aop->execute($request);
$node = 'alipay_trade_refund_response';
$result = $response->$node;
if (isset($result->code) && $result->code === '10000') {
$order->add_order_note(sprintf(__('支付宝退款成功,金额:¥%s', 'woo-alipay'), number_format($refund_amount, 2)));
return true;
}
return new WP_Error('refund_failed', $result->sub_msg ?? $result->msg ?? __('退款失败', 'woo-alipay'));
} catch (Exception $e) {
return new WP_Error('exception', $e->getMessage());
}
}

/**
* 检查支付方式是否可用
*/
public function is_available()
{
$is_available = ('yes' === $this->enabled) ? true : false;

if (!$is_available) {
return false;
}

// 检查主支付宝网关是否配置
$main_gateway = new WC_Alipay(false);
if (!$main_gateway->get_option('appid') || !$main_gateway->get_option('private_key')) {
return false;
}

return $is_available;
}

protected function convert_to_rmb($amount)
{
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-alipay-sdk-helper.php';
return Alipay_SDK_Helper::convert_currency(
$amount,
$this->current_currency,
$this->exchange_rate
);
}

protected function get_order_title($order)
{
$title = get_bloginfo('name') . ' - ' . sprintf(__('订单 #%s', 'woo-alipay'), $order->get_id());
return mb_substr($title, 0, 256);
}

protected function get_order_description($order)
{
$items = array();
foreach ($order->get_items() as $item) {
$items[] = $item->get_name();
}
return mb_substr(implode(', ', $items), 0, 400);
}

protected static function log($message, $level = 'info')
{
if (self::$log_enabled) {
if (empty(self::$log)) {
self::$log = wc_get_logger();
}
self::$log->log($level, $message, array('source' => self::GATEWAY_ID));
}
}
}

View file

@ -1,104 +0,0 @@
<?php

use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;

/**
* 花呗分期支付的 WooCommerce Blocks 支持类
*/
final class WC_Alipay_Installment_Blocks_Support extends AbstractPaymentMethodType {

private $gateway;
protected $name = 'alipay_installment';

public function __construct() {
$this->name = 'alipay_installment';
}

public function initialize() {
$this->settings = get_option( 'woocommerce_alipay_installment_settings', array() );
$gateways = WC()->payment_gateways->payment_gateways();
$this->gateway = isset( $gateways['alipay_installment'] ) ? $gateways['alipay_installment'] : false;
}

public function is_active() {
$enabled = isset( $this->settings['enabled'] ) ? $this->settings['enabled'] : 'no';
return 'yes' === $enabled;
}

public function get_payment_method_script_handles() {
$script_path = 'js/frontend/blocks-installment.js';
$script_asset_path = WOO_ALIPAY_PLUGIN_PATH . 'js/frontend/blocks-installment.asset.php';
$script_asset = file_exists( $script_asset_path )
? require( $script_asset_path )
: array(
'dependencies' => array( 'wc-blocks-registry', 'wp-element', 'wp-html-entities', 'wp-i18n' ),
'version' => WOO_ALIPAY_VERSION
);
$script_url = trailingslashit( WOO_ALIPAY_PLUGIN_URL ) . $script_path;

wp_register_script(
'wc-alipay-installment-payments-blocks',
$script_url,
$script_asset['dependencies'],
$script_asset['version'],
true
);

if ( function_exists( 'wp_set_script_translations' ) ) {
wp_set_script_translations( 'wc-alipay-installment-payments-blocks', 'woo-alipay', WOO_ALIPAY_PLUGIN_PATH . 'languages' );
}

return [ 'wc-alipay-installment-payments-blocks' ];
}

public function get_payment_method_script_handles_for_admin() {
return $this->get_payment_method_script_handles();
}

public function get_payment_method_data() {
$cart_total = WC()->cart ? WC()->cart->get_total('') : 0;
$min_amount = $this->get_setting( 'min_amount', 100 );
$available_periods = $this->get_setting( 'available_periods', array('3', '6', '12') );
// 动态按阈值过滤
$min6 = floatval($this->get_setting('min_amount_6', 0));
$min12 = floatval($this->get_setting('min_amount_12', 0));
$filtered_periods = array();
foreach ($available_periods as $p) {
if ($p === '6' && $min6 > 0 && $cart_total < $min6) { continue; }
if ($p === '12' && $min12 > 0 && $cart_total < $min12) { continue; }
$filtered_periods[] = $p;
}
$available_periods = $filtered_periods;
$default_period = $this->get_setting( 'default_period', '3' );
// 获取汇率并转换金额
$current_currency = get_option('woocommerce_currency');
$exchange_rate = $this->get_setting( 'exchange_rate', 7.0 );
if (!in_array($current_currency, array('CNY', 'RMB'), true)) {
$cart_total = floatval($cart_total) * floatval($exchange_rate);
}
$meets_min_amount = $cart_total >= floatval($min_amount);
return [
'title' => $this->get_setting( 'title', '支付宝花呗分期' ),
'description' => $this->get_setting( 'description', '使用支付宝花呗分期付款支持3期、6期、12期免息或低息分期。' ),
'supports' => $this->get_supported_features(),
'icon' => WOO_ALIPAY_PLUGIN_URL . 'assets/images/alipay-icon.svg',
'minAmount' => floatval($min_amount),
'cartTotal' => floatval($cart_total),
'meetsMinAmount' => $meets_min_amount,
'insufficientBehavior' => $this->get_setting( 'blocks_insufficient_behavior', 'hide' ),
'availablePeriods' => $available_periods,
'defaultPeriod' => $default_period,
'feePayer' => ($this->get_setting('fee_bearer', 'user') === 'seller' ? 'seller' : 'user'),
'showInterestFreeBadge' => ($this->get_setting('show_interest_free_badge', 'yes') === 'yes'),
];
}

public function get_supported_features() {
return $this->gateway ? $this->gateway->supports : ['products'];
}
}

View file

@ -1,641 +0,0 @@
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}

/**
* 花呗分期支付网关
*
* 支持花呗分期付款功能用户可选择3期、6期、12期分期
*/
class WC_Alipay_Installment extends WC_Payment_Gateway
{
const GATEWAY_ID = 'alipay_installment';
protected static $log_enabled = false;
protected static $log = false;
protected $current_currency;
protected $exchange_rate;
protected $order_prefix;
protected $notify_url;
protected $charset;

public function __construct()
{
$this->id = self::GATEWAY_ID;
$this->method_title = __('支付宝花呗分期', 'woo-alipay');
$this->method_description = __('支持花呗分期付款用户可选择3期、6期、12期分期。需要在支付宝商户后台开通花呗分期功能。', 'woo-alipay');
$this->icon = WOO_ALIPAY_PLUGIN_URL . 'assets/images/alipay-icon.svg';
$this->has_fields = true; // 在结账页面显示分期选择
$this->charset = strtolower(get_bloginfo('charset'));
if (!in_array($this->charset, array('gbk', 'utf-8'), true)) {
$this->charset = 'utf-8';
}
// 加载设置
$this->init_form_fields();
$this->init_settings();
// 设置属性
$this->title = $this->get_option('title', __('支付宝花呗分期', 'woo-alipay'));
$this->description = $this->get_option('description');
$this->enabled = $this->get_option('enabled');
$this->current_currency = get_option('woocommerce_currency');
$this->exchange_rate = $this->get_option('exchange_rate');
$this->order_prefix = $this->get_option('order_prefix', 'HBFQ');
$this->notify_url = WC()->api_request_url('WC_Alipay_Installment');
self::$log_enabled = ('yes' === $this->get_option('debug', 'no'));
// 支持的功能
$this->supports = array(
'products',
'refunds',
);
// 添加钩子
add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options'));
add_action('woocommerce_receipt_' . $this->id, array($this, 'receipt_page'));
add_action('woocommerce_api_wc_alipay_installment', array($this, 'check_alipay_response'));
add_action('wp_enqueue_scripts', array($this, 'payment_scripts'));
}

/**
* 初始化表单字段
*/
public function init_form_fields()
{
$this->form_fields = array(
'enabled' => array(
'title' => __('启用/禁用', 'woo-alipay'),
'type' => 'checkbox',
'label' => __('启用支付宝花呗分期', 'woo-alipay'),
'default' => 'no',
),
'title' => array(
'title' => __('标题', 'woo-alipay'),
'type' => 'text',
'description' => __('用户在结账时看到的支付方式名称', 'woo-alipay'),
'default' => __('支付宝花呗分期', 'woo-alipay'),
'desc_tip' => true,
),
'description' => array(
'title' => __('描述', 'woo-alipay'),
'type' => 'textarea',
'description' => __('支付方式描述,显示在结账页面', 'woo-alipay'),
'default' => __('使用支付宝花呗分期付款支持3期、6期、12期免息或低息分期。', 'woo-alipay'),
'desc_tip' => true,
),
'alipay_config' => array(
'title' => __('支付宝配置', 'woo-alipay'),
'type' => 'title',
'description' => __('使用主支付宝网关的配置App ID、公钥、私钥等', 'woo-alipay'),
),
'installment_settings' => array(
'title' => __('分期设置', 'woo-alipay'),
'type' => 'title',
),
'show_interest_free_badge' => array(
'title' => __('显示“免息”标识', 'woo-alipay'),
'type' => 'checkbox',
'label' => __('在分期选项后显示“免息”标识(当商家承担手续费时)', 'woo-alipay'),
'default' => 'yes',
'desc_tip' => true,
),
'fee_bearer' => array(
'title' => __('分期手续费承担方', 'woo-alipay'),
'type' => 'select',
'description' => __('选择分期手续费由谁承担。用户承担将会在支付宝端向用户收取手续费;商家承担则由商家承担。', 'woo-alipay'),
'default' => 'user',
'options' => array(
'user' => __('用户承担', 'woo-alipay'),
'seller' => __('商家承担', 'woo-alipay'),
),
'desc_tip' => true,
),
'min_amount_6' => array(
'title' => __('6期最小金额', 'woo-alipay'),
'type' => 'number',
'description' => __('达到此金额才显示6期选项留空或0表示不限制', 'woo-alipay'),
'default' => '',
'desc_tip' => true,
'custom_attributes' => array(
'min' => '0',
'step' => '1',
),
),
'min_amount_12' => array(
'title' => __('12期最小金额', 'woo-alipay'),
'type' => 'number',
'description' => __('达到此金额才显示12期选项留空或0表示不限制', 'woo-alipay'),
'default' => '',
'desc_tip' => true,
'custom_attributes' => array(
'min' => '0',
'step' => '1',
),
),
'min_amount' => array(
'title' => __('最小分期金额', 'woo-alipay'),
'type' => 'number',
'description' => __('订单金额低于此值时不显示分期选项(人民币)', 'woo-alipay'),
'default' => '100',
'desc_tip' => true,
'custom_attributes' => array(
'min' => '1',
'step' => '1',
),
),
'available_periods' => array(
'title' => __('可用分期期数', 'woo-alipay'),
'type' => 'multiselect',
'description' => __('选择允许的分期期数', 'woo-alipay'),
'default' => array('3', '6', '12'),
'options' => array(
'3' => __('3期', 'woo-alipay'),
'6' => __('6期', 'woo-alipay'),
'12' => __('12期', 'woo-alipay'),
),
'desc_tip' => true,
'class' => 'wc-enhanced-select',
),
'default_period' => array(
'title' => __('默认分期期数', 'woo-alipay'),
'type' => 'select',
'description' => __('用户未选择时的默认分期期数', 'woo-alipay'),
'default' => '3',
'options' => array(
'3' => __('3期', 'woo-alipay'),
'6' => __('6期', 'woo-alipay'),
'12' => __('12期', 'woo-alipay'),
),
'desc_tip' => true,
),
'blocks_insufficient_behavior' => array(
'title' => __('结账区块金额不足行为', 'woo-alipay'),
'type' => 'select',
'description' => __('当订单金额低于最小分期金额时,在结账区块中隐藏支付方式或显示提示。', 'woo-alipay'),
'default' => 'hide',
'options' => array(
'hide' => __('隐藏(推荐)', 'woo-alipay'),
'show' => __('显示提示', 'woo-alipay'),
),
'desc_tip' => true,
),
'order_prefix' => array(
'title' => __('订单号前缀', 'woo-alipay'),
'type' => 'text',
'description' => __('花呗分期订单号的前缀,便于区分', 'woo-alipay'),
'default' => 'HBFQ',
'desc_tip' => true,
),
'debug' => array(
'title' => __('调试日志', 'woo-alipay'),
'type' => 'checkbox',
'label' => __('启用日志记录', 'woo-alipay'),
'default' => 'no',
'description' => sprintf(
__('记录花呗分期相关日志到 %s', 'woo-alipay'),
'<code>' . WC_Log_Handler_File::get_log_file_path($this->id) . '</code>'
),
),
);
// 如果不是人民币,添加汇率设置
if (!in_array($this->current_currency, array('CNY', 'RMB'), true)) {
$this->form_fields['exchange_rate'] = array(
'title' => __('汇率', 'woo-alipay'),
'type' => 'number',
'description' => sprintf(
__('设置 %s 与人民币的汇率', 'woo-alipay'),
$this->current_currency
),
'default' => '7.0',
'desc_tip' => true,
'custom_attributes' => array(
'step' => '0.01',
'min' => '0.01',
),
);
}
}

/**
* 在结账页面显示分期选择
*/
public function payment_fields()
{
// 显示描述
if ($this->description) {
echo wpautop(wptexturize($this->description));
}
// 获取购物车总额
$cart_total = WC()->cart->get_total('');
$min_amount = floatval($this->get_option('min_amount', 100));
$available_periods = $this->get_option('available_periods', array('3', '6', '12'));
$default_period = $this->get_option('default_period', '3');
// 转换为人民币
$rmb_total = $this->convert_to_rmb($cart_total);
if ($rmb_total < $min_amount) {
echo '<p class="alipay-installment-notice">' .
sprintf(__('订单金额需满 ¥%s 才能使用花呗分期', 'woo-alipay'), $min_amount) .
'</p>';
return;
}
// 动态过滤可用分期期数(根据阈值)
$filtered_periods = array();
foreach ($available_periods as $p) {
$p = (string) $p;
if ($p === '6') {
$min6 = floatval($this->get_option('min_amount_6', 0));
if ($min6 > 0 && $rmb_total < $min6) { continue; }
}
if ($p === '12') {
$min12 = floatval($this->get_option('min_amount_12', 0));
if ($min12 > 0 && $rmb_total < $min12) { continue; }
}
$filtered_periods[] = $p;
}
?>
<div class="alipay-installment-selector">
<p><strong><?php _e('选择分期期数:', 'woo-alipay'); ?></strong></p>
<ul class="installment-periods">
<?php foreach ($filtered_periods as $period) : ?>
<li>
<label>
<input type="radio"
name="alipay_installment_period"
value="<?php echo esc_attr($period); ?>"
<?php checked($period, $default_period); ?> />
<span class="period-label">
<?php echo sprintf(__('%s期', 'woo-alipay'), $period); ?>
</span>
<span class="period-amount">
<?php
$monthly = $rmb_total / intval($period);
echo sprintf(__('每期 ¥%s', 'woo-alipay'), number_format($monthly, 2));
?>
</span>
<?php if ( $this->get_option('fee_bearer', 'user') === 'seller' && 'yes' === $this->get_option('show_interest_free_badge', 'yes') ) : ?>
<span class="alipay-badge alipay-badge--free">
<?php _e('免息', 'woo-alipay'); ?>
</span>
<?php endif; ?>
</label>
</li>
<?php endforeach; ?>
</ul>
<p class="alipay-installment-fee-note">
<?php
$fee_bearer = $this->get_option('fee_bearer', 'user');
echo $fee_bearer === 'seller'
? __('免息分期(手续费由商家承担)', 'woo-alipay')
: __('可能产生分期手续费,以支付宝支付页面为准', 'woo-alipay');
?>
</p>
</div>
<?php
}

/**
* 加载前端脚本
*/
public function payment_scripts()
{
if (!is_checkout()) {
return;
}
wp_enqueue_style(
'alipay-installment',
WOO_ALIPAY_PLUGIN_URL . 'css/alipay-installment.css',
array(),
WOO_ALIPAY_VERSION
);
wp_enqueue_script(
'alipay-installment',
WOO_ALIPAY_PLUGIN_URL . 'js/alipay-installment.js',
array('jquery'),
WOO_ALIPAY_VERSION,
true
);
}

/**
* 处理支付
*/
public function process_payment($order_id)
{
$order = wc_get_order($order_id);
// 获取分期期数 - 支持传统表单和 Blocks
$installment_period = $this->get_option('default_period', '3');
// 从传统表单获取
if (isset($_POST['alipay_installment_period'])) {
$installment_period = sanitize_text_field($_POST['alipay_installment_period']);
}
// 从 Blocks 获取
elseif (isset($_POST['payment_data'])) {
$payment_data = json_decode(wp_unslash($_POST['payment_data']), true);
if (isset($payment_data['alipay_installment_period'])) {
$installment_period = sanitize_text_field($payment_data['alipay_installment_period']);
}
}
// 保存分期期数到订单
$order->update_meta_data('_alipay_installment_period', $installment_period);
$order->save();
// 标记订单为待支付
$order->update_status('pending', __('等待花呗分期支付', 'woo-alipay'));
// 清空购物车
WC()->cart->empty_cart();
// 跳转到支付页面
return array(
'result' => 'success',
'redirect' => $order->get_checkout_payment_url(true),
);
}

/**
* 收银页面 - 生成支付表单
*/
public function receipt_page($order_id)
{
$order = wc_get_order($order_id);
if (!$order || $order->is_paid()) {
return;
}
// 加载辅助类
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-alipay-sdk-helper.php';
// 获取主支付宝网关配置
$main_gateway = new WC_Alipay(false);
$config = Alipay_SDK_Helper::get_alipay_config(array(
'appid' => $main_gateway->get_option('appid'),
'private_key' => $main_gateway->get_option('private_key'),
'public_key' => $main_gateway->get_option('public_key'),
'sandbox' => $main_gateway->get_option('sandbox'),
));
// 创建支付宝服务
$aop = Alipay_SDK_Helper::create_alipay_service($config);
if (!$aop) {
$order->update_status('failed', __('创建支付宝服务失败', 'woo-alipay'));
wc_add_notice(__('支付初始化失败,请稍后重试', 'woo-alipay'), 'error');
return;
}
// 获取订单信息
$total = $this->convert_to_rmb($order->get_total());
$installment_period = $order->get_meta('_alipay_installment_period');
$out_trade_no = Alipay_SDK_Helper::generate_out_trade_no($order_id, $this->order_prefix);
// 保存商户订单号
$order->update_meta_data('_alipay_out_trade_no', $out_trade_no);
$order->save();
try {
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/AopClient.php';
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/request/AlipayTradePagePayRequest.php';
$request = new AlipayTradePagePayRequest();
// 设置业务参数
$biz_content = array(
'out_trade_no' => $out_trade_no,
'total_amount' => Alipay_SDK_Helper::format_amount($total),
'subject' => $this->get_order_title($order),
'body' => $this->get_order_description($order),
'product_code' => 'FAST_INSTANT_TRADE_PAY',
// 花呗分期参数
'enable_pay_channels' => 'pcreditpayInstallment',
'extend_params' => array(
'hb_fq_num' => $installment_period,
'hb_fq_seller_percent' => ($this->get_option('fee_bearer', 'user') === 'seller' ? '100' : '0'),
),
);
$request->setBizContent(json_encode($biz_content));
$request->setReturnUrl($order->get_checkout_order_received_url());
$request->setNotifyUrl($this->notify_url);
// 生成支付表单
$html = $aop->pageExecute($request, 'POST');
self::log('花呗分期支付请求: ' . print_r($biz_content, true));
echo $html;
} catch (Exception $e) {
self::log('花呗分期支付异常: ' . $e->getMessage(), 'error');
$order->update_status('failed', $e->getMessage());
wc_add_notice(__('支付请求失败,请稍后重试', 'woo-alipay'), 'error');
}
}

/**
* 检查支付宝响应
*/
public function check_alipay_response()
{
// 加载辅助类
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-alipay-sdk-helper.php';
// 获取支付宝公钥
$main_gateway = new WC_Alipay(false);
$alipay_public_key = $main_gateway->get_option('public_key');
// 验证签名
if (!Alipay_SDK_Helper::verify_notify($_POST, $alipay_public_key)) {
self::log('花呗分期通知签名验证失败', 'error');
echo 'fail';
exit;
}
$out_trade_no = $_POST['out_trade_no'] ?? '';
$trade_no = $_POST['trade_no'] ?? '';
$trade_status = $_POST['trade_status'] ?? '';
self::log('花呗分期支付通知: ' . print_r($_POST, true));
// 查找订单
$orders = wc_get_orders(array(
'meta_key' => '_alipay_out_trade_no',
'meta_value' => $out_trade_no,
'limit' => 1,
));
if (empty($orders)) {
self::log('未找到订单: ' . $out_trade_no, 'error');
echo 'fail';
exit;
}
$order = $orders[0];
// 处理支付结果
if ($trade_status === 'TRADE_SUCCESS' || $trade_status === 'TRADE_FINISHED') {
if (!$order->is_paid()) {
$order->payment_complete($trade_no);
$order->add_order_note(
sprintf(__('花呗分期支付完成 - 交易号: %s', 'woo-alipay'), $trade_no)
);
}
echo 'success';
} else {
echo 'fail';
}
exit;
}

/**
* 处理退款
*/
public function process_refund($order_id, $amount = null, $reason = '')
{
$order = wc_get_order($order_id);
if (!$order) {
return new WP_Error('error', __('订单不存在', 'woo-alipay'));
}
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-alipay-sdk-helper.php';
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/AopClient.php';
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/request/AlipayTradeRefundRequest.php';
$main_gateway = new WC_Alipay(false);
$config = Alipay_SDK_Helper::get_alipay_config(array(
'appid' => $main_gateway->get_option('appid'),
'private_key' => $main_gateway->get_option('private_key'),
'public_key' => $main_gateway->get_option('public_key'),
'sandbox' => $main_gateway->get_option('sandbox'),
));
$aop = Alipay_SDK_Helper::create_alipay_service($config);
if (!$aop) {
return new WP_Error('sdk_error', __('创建支付宝服务失败', 'woo-alipay'));
}
$out_trade_no = $order->get_meta('_alipay_out_trade_no');
if (!$out_trade_no) {
$out_trade_no = Alipay_SDK_Helper::generate_out_trade_no($order_id, $this->order_prefix);
}
$refund_amount = $amount ? floatval($amount) : floatval($order->get_total());
$refund_reason = $reason ? $reason : __('订单退款', 'woo-alipay');
try {
$request = new AlipayTradeRefundRequest();
$biz_content = array(
'out_trade_no' => $out_trade_no,
'refund_amount' => Alipay_SDK_Helper::format_amount($refund_amount),
'refund_reason' => $refund_reason,
);
$request->setBizContent(json_encode($biz_content));
$response = $aop->execute($request);
$node = 'alipay_trade_refund_response';
$result = $response->$node;
if (isset($result->code) && $result->code === '10000') {
$order->add_order_note(sprintf(__('支付宝退款成功,金额:¥%s', 'woo-alipay'), number_format($refund_amount, 2)));
return true;
}
return new WP_Error('refund_failed', $result->sub_msg ?? $result->msg ?? __('退款失败', 'woo-alipay'));
} catch (Exception $e) {
return new WP_Error('exception', $e->getMessage());
}
}

/**
* 检查支付方式是否可用
*/
public function is_available()
{
$is_available = ('yes' === $this->enabled) ? true : false;

if (!$is_available) {
return false;
}

// 检查主支付宝网关是否配置
$main_gateway = new WC_Alipay(false);
if (!$main_gateway->get_option('appid') || !$main_gateway->get_option('private_key')) {
return false;
}

// 检查最小金额要求
if (WC()->cart) {
$cart_total = WC()->cart->get_total('');
$min_amount = floatval($this->get_option('min_amount', 100));
$rmb_total = $this->convert_to_rmb($cart_total);
if ($rmb_total < $min_amount) {
return false;
}
}

return $is_available;
}

/**
* 转换为人民币
*/
protected function convert_to_rmb($amount)
{
return Alipay_SDK_Helper::convert_currency(
$amount,
$this->current_currency,
$this->exchange_rate
);
}

/**
* 获取订单标题
*/
protected function get_order_title($order)
{
$title = get_bloginfo('name') . ' - ' . sprintf(__('订单 #%s', 'woo-alipay'), $order->get_id());
return mb_substr($title, 0, 256);
}

/**
* 获取订单描述
*/
protected function get_order_description($order)
{
$items = array();
foreach ($order->get_items() as $item) {
$items[] = $item->get_name();
}
return mb_substr(implode(', ', $items), 0, 400);
}

/**
* 记录日志
*/
protected static function log($message, $level = 'info')
{
if (self::$log_enabled) {
if (empty(self::$log)) {
self::$log = wc_get_logger();
}
self::$log->log($level, $message, array('source' => self::GATEWAY_ID));
}
}
}

View file

@ -0,0 +1,53 @@
<?php
if ( ! defined( 'ABSPATH' ) ) { exit; }

class WC_Alipay_Subscription_UI {
public static function init() {
// Thank You 页签约提示
add_action( 'woocommerce_thankyou', [ __CLASS__, 'maybe_render_thankyou_sign' ], 50 );

// 订阅详情页签约按钮Woo Subscriptions
add_action( 'woocommerce_account_view-subscription_endpoint', [ __CLASS__, 'render_view_subscription_sign' ] );
}

protected static function can_offer_sign( $user_id ) {
if ( ! class_exists( 'WC_Alipay_Agreement' ) ) { return false; }
$enabled = get_option( 'woocommerce_alipay_settings', [] )['enable_auto_renew'] ?? 'no';
if ( 'yes' !== $enabled ) { return false; }
return ! WC_Alipay_Agreement::has_user_agreement( $user_id );
}

public static function maybe_render_thankyou_sign( $order_id ) {
if ( ! is_user_logged_in() || ! $order_id ) { return; }
$user_id = get_current_user_id();
if ( ! self::can_offer_sign( $user_id ) ) { return; }

// 若订单包含订阅则更强提示(没有函数也不阻塞)
if ( function_exists( 'wcs_order_contains_subscription' ) && ! wcs_order_contains_subscription( $order_id ) ) {
return; // 仅在订阅相关订单的 Thank You 显示
}

$return_url = wc_get_endpoint_url( 'view-subscription', '', wc_get_page_permalink( 'myaccount' ) );
$sign_url = add_query_arg( [ 'return_url' => rawurlencode( $return_url ) ], WC()->api_request_url( 'WC_Alipay_Agreement_Start' ) );
echo '<div class="woocommerce-message" style="margin-top:15px">'
. esc_html__( '为确保到期自动续费,请授权支付宝周期扣款。', 'woo-alipay' )
. ' <a class="button" href="' . esc_url( $sign_url ) . '">' . esc_html__( '授权支付宝自动续费', 'woo-alipay' ) . '</a>'
. '</div>';
}

public static function render_view_subscription_sign( $subscription_id ) {
if ( ! is_user_logged_in() ) { return; }
$user_id = get_current_user_id();
if ( ! self::can_offer_sign( $user_id ) ) { return; }

$return_url = wc_get_account_endpoint_url( 'subscriptions' );
$sign_url = add_query_arg( [ 'return_url' => rawurlencode( $return_url ) ], WC()->api_request_url( 'WC_Alipay_Agreement_Start' ) );

echo '<div class="woocommerce-info" style="margin:15px 0">'
. '<p>' . esc_html__( '尚未授权支付宝自动续费。授权后,到期将自动从你绑定的支付宝扣款。', 'woo-alipay' ) . '</p>'
. '<p><a class="button" href="' . esc_url( $sign_url ) . '">' . esc_html__( '立即授权', 'woo-alipay' ) . '</a></p>'
. '</div>';
}
}

WC_Alipay_Subscription_UI::init();

View file

@ -63,6 +63,7 @@ class WC_Alipay extends WC_Payment_Gateway
'subscription_amount_changes',
'subscription_date_changes',
'multiple_subscriptions',
'tokenization',
);

self::$log_enabled = ('yes' === $this->get_option('debug', 'no'));
@ -74,6 +75,12 @@ class WC_Alipay extends WC_Payment_Gateway
$this->setup_form_fields();
$this->init_settings();


// Register subscription scheduled payment hook
if ( class_exists('WC_Subscriptions') || function_exists('wcs_order_contains_subscription') || function_exists('wcs_is_subscription') ) {
add_action('woocommerce_scheduled_subscription_payment_' . $this->id, array($this, 'scheduled_subscription_payment'), 10, 2);
}

if ($init_hooks) {
// Add save gateway options callback
add_action('woocommerce_update_options_payment_gateways_' . $this->id, array(
@ -101,6 +108,100 @@ class WC_Alipay extends WC_Payment_Gateway
}
}

/**
* Woo Subscriptions: scheduled payment callback
*
* @param float $amount_to_charge
* @param WC_Order $renewal_order
*/
public function scheduled_subscription_payment( $amount_to_charge, $renewal_order )
{
try {
if ( 'yes' !== $this->get_option( 'enable_auto_renew', 'no' ) ) {
$renewal_order->add_order_note( __( '未启用自动续费,跳过代扣。', 'woo-alipay' ) );
$renewal_order->update_status( 'failed', __( '自动续费未启用', 'woo-alipay' ) );
return;
}

$user_id = $renewal_order->get_user_id();
if ( ! $user_id || ! class_exists( 'WC_Alipay_Agreement' ) ) {
$renewal_order->update_status( 'failed', __( '找不到用户或协议管理不可用。', 'woo-alipay' ) );
return;
}

$agreement_no = WC_Alipay_Agreement::get_user_agreement_no( $user_id );
if ( ! $agreement_no ) {
$renewal_order->update_status( 'failed', __( '未查询到支付宝扣款协议,请先完成签约。', 'woo-alipay' ) );
return;
}

require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-alipay-sdk-helper.php';
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/AopClient.php';
require_once WOO_ALIPAY_PLUGIN_PATH . 'lib/alipay/aop/request/AlipayTradeCreateRequest.php';

$config = Alipay_SDK_Helper::get_alipay_config( array(
'appid' => $this->get_option('appid'),
'private_key' => $this->get_option('private_key'),
'public_key' => $this->get_option('public_key'),
'sandbox' => $this->get_option('sandbox'),
) );

$aop = Alipay_SDK_Helper::create_alipay_service( $config );
if ( ! $aop ) {
$renewal_order->update_status( 'failed', __( '创建支付宝服务失败(自动续费)。', 'woo-alipay' ) );
return;
}

$out_trade_no = 'SubR' . $renewal_order->get_id() . '-' . current_time('timestamp');
// 记录到订单元数据,便于回调查询定位
$renewal_order->update_meta_data( '_alipay_out_trade_no', $out_trade_no );
$renewal_order->save();

$total = $this->maybe_convert_amount( $amount_to_charge );
$subject = $this->get_option( 'auto_renew_subject_prefix', __( '订阅续费', 'woo-alipay' ) ) . ' - #' . $renewal_order->get_id();

$product_code = apply_filters( 'woo_alipay_agreement_trade_product_code', $this->get_option( 'agreement_product_code', 'CYCLE_PAY_AUTH' ), $renewal_order );
$biz = array(
'out_trade_no' => $out_trade_no,
'total_amount' => $total,
'subject' => $subject,
'product_code' => $product_code,
'agreement_params' => array(
'agreement_no' => $agreement_no,
),
);

$biz = apply_filters( 'woo_alipay_agreement_trade_biz_content', $biz, $renewal_order, $agreement_no );

$request = new AlipayTradeCreateRequest();
$request->setBizContent( wp_json_encode( $biz ) );
$request->setNotifyUrl( apply_filters( 'woo_alipay_gateway_notify_url', $this->notify_url, $renewal_order->get_id() ) );

$response = $aop->execute( $request );
$node = 'alipay_trade_create_response';
$result = $response->$node ?? null;

if ( ! $result || ! isset( $result->code ) || '10000' !== $result->code ) {
self::log( __METHOD__ . ' TradeCreate error: ' . wc_print_r( $response, true ), 'error' );
$renewal_order->update_status( 'failed', __( '支付宝代扣下单失败。', 'woo-alipay' ) );
return;
}

// 可选:立即查询一次状态
$query = Alipay_SDK_Helper::query_order( $out_trade_no, '', $config );
if ( ! is_wp_error( $query ) && ! empty( $query['trade_status'] ) && in_array( $query['trade_status'], array( 'TRADE_SUCCESS', 'TRADE_FINISHED' ), true ) ) {
$renewal_order->payment_complete( $query['trade_no'] );
$renewal_order->add_order_note( sprintf( __( '自动续费成功,交易号:%s', 'woo-alipay' ), $query['trade_no'] ) );
} else {
// 等待异步通知回调完成订单
$renewal_order->add_order_note( __( '已发起支付宝代扣,等待异步通知确认。', 'woo-alipay' ) );
}
} catch ( Exception $e ) {
self::log( __METHOD__ . ' exception: ' . $e->getMessage(), 'error' );
$renewal_order->update_status( 'failed', $e->getMessage() );
}
}

protected function setup_form_fields()
{
$this->form_fields = array(
@ -195,16 +296,62 @@ class WC_Alipay extends WC_Payment_Gateway
),
'desc_tip' => false,
),
'advanced_settings_title' => array(
'title' => __('高级设置', 'woo-alipay'),
'type' => 'title',
'description' => __('配置汇率转换和连接测试等高级功能', 'woo-alipay'),
),

);

// 将“支付增强功能”分组提前到“环境与调试”之后
$this->add_payment_enhancement_settings();

// 后续是“高级设置”和“订阅与自动续费(实验性)”
$this->form_fields = array_merge(
$this->form_fields,
array(
'advanced_settings_title' => array(
'title' => __('高级设置', 'woo-alipay'),
'type' => 'title',
'description' => __('配置汇率转换和连接测试等高级功能', 'woo-alipay'),
),
)
);

// Subscriptions & Auto-renew (Experimental)

// 订阅与自动续费(实验性)分组与字段
$this->form_fields['subscriptions_title'] = array(
'title' => __('订阅与自动续费(实验性)', 'woo-alipay'),
'type' => 'title',
'description' => __('启用后,支持 WooCommerce Subscriptions 的自动续费。需要先在支付宝签约周期扣款。', 'woo-alipay'),
);
$this->form_fields['enable_auto_renew'] = array(
'title' => __('启用自动续费', 'woo-alipay'),
'type' => 'checkbox',
'label' => __('允许通过支付宝协议代扣进行订阅续费', 'woo-alipay'),
'default' => 'no',
);
$this->form_fields['agreement_product_code'] = array(
'title' => __('签约/代扣产品码', 'woo-alipay'),
'type' => 'text',
'default' => 'CYCLE_PAY_AUTH',
'description' => __('用于协议签约与代扣的产品码。不同商户开通能力可能不同,可通过过滤器覆盖。', 'woo-alipay'),
'desc_tip' => true,
);
$this->form_fields['auto_renew_subject_prefix'] = array(
'title' => __('续费订单标题前缀', 'woo-alipay'),
'type' => 'text',
'default' => __('订阅续费', 'woo-alipay'),
);
// 添加支付增强功能设置
$this->add_payment_enhancement_settings();
// 仅当安装并启用了 WooCommerce Subscriptions 时,展示自动续费设置
if ( ! ( class_exists('WC_Subscriptions') || function_exists('wcs_order_contains_subscription') || function_exists('wcs_is_subscription') ) ) {
unset(
$this->form_fields['enable_auto_renew'],
$this->form_fields['agreement_product_code'],
$this->form_fields['auto_renew_subject_prefix']
);
if ( isset( $this->form_fields['subscriptions_title'] ) ) {
$this->form_fields['subscriptions_title']['description'] = __( '需要安装并启用 WooCommerce Subscriptions 才能设置自动续费。', 'woo-alipay' );
}
}

if (!in_array($this->current_currency, $this->supported_currencies, true)) {
$current_rate = $this->get_option('exchange_rate', '7.0');
@ -653,7 +800,7 @@ class WC_Alipay extends WC_Payment_Gateway
$config = array(
'app_id' => $this->get_option('appid'),
'merchant_private_key' => $this->get_option('private_key'),
'notify_url' => $this->notify_url,
'notify_url' => apply_filters('woo_alipay_gateway_notify_url', $this->notify_url, $order_id),
'return_url' => apply_filters('woo_alipay_gateway_return_url', ($order) ? $order->get_checkout_order_received_url() : get_home_url()),
'charset' => $this->charset,
'sign_type' => 'RSA2',
@ -843,11 +990,50 @@ class WC_Alipay extends WC_Payment_Gateway
echo '</p>';
echo '</div>';


// 实用端点与工具
$notify_url = apply_filters( 'woo_alipay_gateway_notify_url', $this->notify_url, 0 );
echo '<div class="card" style="padding:12px; margin:12px 0;">';
echo '<h2 style="margin-top:0;">' . esc_html__( '工具与端点', 'woo-alipay' ) . '</h2>';
echo '<p>' . esc_html__( '异步通知 URL请在支付宝开放平台中配置为支付结果通知 URL', 'woo-alipay' ) . '</p>';
echo '<p><code id="woo-alipay-notify-url">' . esc_html( $notify_url ) . '</code> ';
echo '<button type="button" class="button" onclick="wooAlipayCopy(\'#woo-alipay-notify-url\')">' . esc_html__( '复制', 'woo-alipay' ) . '</button></p>';

// 若支持订阅,展示签约相关端点
$subs_available = ( class_exists('WC_Subscriptions') || function_exists('wcs_order_contains_subscription') || function_exists('wcs_is_subscription') );
if ( $subs_available ) {
$start_url = WC()->api_request_url( 'WC_Alipay_Agreement_Start' );
$notify_agre = WC()->api_request_url( 'WC_Alipay_Agreement_Notify' );
$return_agre = WC()->api_request_url( 'WC_Alipay_Agreement_Return' );
echo '<hr/>';
echo '<p>' . esc_html__( '签约端点(用于支付宝协议授权与回调)', 'woo-alipay' ) . '</p>';
echo '<ul style="margin-left:1em;">';
echo '<li>' . esc_html__( '签约启动', 'woo-alipay' ) . ': <code id="woo-alipay-sign-start">' . esc_html( $start_url ) . '</code> <button type="button" class="button" onclick="wooAlipayCopy(\'#woo-alipay-sign-start\')">' . esc_html__( '复制', 'woo-alipay' ) . '</button></li>';
echo '<li>' . esc_html__( '签约通知', 'woo-alipay' ) . ': <code id="woo-alipay-sign-notify">' . esc_html( $notify_agre ) . '</code> <button type="button" class="button" onclick="wooAlipayCopy(\'#woo-alipay-sign-notify\')">' . esc_html__( '复制', 'woo-alipay' ) . '</button></li>';
echo '<li>' . esc_html__( '签约返回', 'woo-alipay' ) . ': <code id="woo-alipay-sign-return">' . esc_html( $return_agre ) . '</code> <button type="button" class="button" onclick="wooAlipayCopy(\'#woo-alipay-sign-return\')">' . esc_html__( '复制', 'woo-alipay' ) . '</button></li>';
echo '</ul>';
}
echo '</div>';

echo '<table class="form-table woo-alipay-settings">';

$this->generate_settings_html();

echo '</table>';

// 简易复制函数
echo '<script type="text/javascript">function wooAlipayCopy(sel){try{var el=document.querySelector(sel);if(!el)return;var r=document.createRange();r.selectNode(el);var s=window.getSelection();s.removeAllRanges();s.addRange(r);document.execCommand("copy");s.removeAllRanges();}catch(e){console&&console.error(e);}}</script>';
}

// Provider state methods for WooCommerce Payments list badges
public function is_account_connected() {
return (bool) ( $this->get_option('appid') && $this->get_option('private_key') && $this->get_option('public_key') );
}

public function needs_setup() {
return ! $this->is_account_connected();
}

public function is_test_mode() {
return 'yes' === $this->get_option('sandbox');
}

public function check_alipay_response()
@ -861,9 +1047,23 @@ class WC_Alipay extends WC_Payment_Gateway
$fund_bill_list = isset($_POST['fund_bill_list']) ? stripslashes(sanitize_text_field($_POST['fund_bill_list'])) : '';
$needs_reply = false;
$error = false;
$out_trade_no_parts = explode('-', str_replace('WooA', '', $out_trade_no));
$order_id = absint(array_shift($out_trade_no_parts));
$order = wc_get_order($order_id);

// 先尝试通过既有规则WooA前缀解析订单ID
$order = null;
$order_id = 0;
if ( strpos( $out_trade_no, 'WooA' ) === 0 ) {
$out_trade_no_parts = explode('-', str_replace('WooA', '', $out_trade_no));
$order_id = absint(array_shift($out_trade_no_parts));
$order = wc_get_order($order_id);
}
// 若无法解析或未找到订单,改为通过订单元数据定位(适配自动续费 SubR*
if ( ! $order ) {
$orders = wc_get_orders( array( 'meta_key' => '_alipay_out_trade_no', 'meta_value' => $out_trade_no, 'limit' => 1 ) );
if ( ! empty( $orders ) ) {
$order = $orders[0];
$order_id = $order->get_id();
}
}
$order_check = ($order instanceof WC_Order);
if (!$order_check) {

View file

@ -35,6 +35,9 @@ class Woo_Alipay {
// Add WooCommerce Blocks support
$this->woocommerce_gateway_alipay_woocommerce_block_support();

// Enhance Payments providers response with contextual links for Alipay gateways
add_filter( 'rest_post_dispatch', array( $this, 'filter_payments_providers_response' ), 10, 3 );
}
}

@ -151,39 +154,53 @@ class Woo_Alipay {
}
}

public function add_admin_scripts( $hook ) {
public function add_admin_scripts( $hook ) {

if ( 'woocommerce_page_wc-settings' === $hook ) {
$debug = (bool) ( constant( 'WP_DEBUG' ) );
$css_ext = ( $debug ) ? '.css' : '.min.css';
$js_ext = ( $debug ) ? '.js' : '.min.js';
$version_css = filemtime( WOO_ALIPAY_PLUGIN_PATH . 'css/admin/main' . $css_ext );
$version_js = filemtime( WOO_ALIPAY_PLUGIN_PATH . 'js/admin/main' . $js_ext );
if ( 'woocommerce_page_wc-settings' !== $hook ) {
return;
}

wp_enqueue_style(
'woo-alipay-main-style',
WOO_ALIPAY_PLUGIN_URL . 'css/admin/main' . $css_ext,
array(),
$version_css
);
// Only load our admin assets on our gateway settings sections, not on the Payments list view.
$tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : '';
$section = isset( $_GET['section'] ) ? sanitize_key( wp_unslash( $_GET['section'] ) ) : '';
$our_sections = array( 'alipay', 'alipay_installment', 'alipay_facetopay' );
if ( 'checkout' !== $tab || ! in_array( $section, $our_sections, true ) ) {
return;
}

$parameters = array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'debug' => $debug,
);
$debug = (bool) ( constant( 'WP_DEBUG' ) );
$css_ext = ( $debug ) ? '.css' : '.min.css';
$js_ext = ( $debug ) ? '.js' : '.min.js';
$version_css = filemtime( WOO_ALIPAY_PLUGIN_PATH . 'css/admin/main' . $css_ext );
$version_js = filemtime( WOO_ALIPAY_PLUGIN_PATH . 'js/admin/main' . $js_ext );

wp_enqueue_script(
'woo-alipay-admin-script',
WOO_ALIPAY_PLUGIN_URL . 'js/admin/main' . $js_ext,
array( 'jquery' ),
$version_js,
true
);
wp_localize_script( 'woo-alipay-admin-script', 'WooAlipay', $parameters );
}
wp_enqueue_style(
'woo-alipay-main-style',
WOO_ALIPAY_PLUGIN_URL . 'css/admin/main' . $css_ext,
array(),
$version_css
);

$parameters = array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'debug' => $debug,
);

wp_enqueue_script(
'woo-alipay-admin-script',
WOO_ALIPAY_PLUGIN_URL . 'js/admin/main' . $js_ext,
array( 'jquery' ),
$version_js,
true
);
wp_localize_script( 'woo-alipay-admin-script', 'WooAlipay', $parameters );
}

public function add_admin_pages() {
// If the dedicated Reconcile Pro extension is active, avoid adding a duplicate menu.
if ( class_exists( 'Woo_Alipay_Reconcile_Admin' ) ) {
return;
}
add_submenu_page(
'woocommerce',
__( '支付宝对账工具', 'woo-alipay' ),
@ -194,6 +211,88 @@ class Woo_Alipay {
);
}

/**
* Inject provider links into the WooCommerce Payments providers REST response.
*/
public function filter_payments_providers_response( $response, $server, $request ) {
try {
// Allow site owners to disable this injection for troubleshooting.
if ( false === apply_filters( 'woo_alipay_enable_payments_links_injection', true ) ) {
return $response;
}

if ( ! $response || ! is_a( $response, 'WP_REST_Response' ) ) {
return $response;
}

$route = is_object( $request ) && method_exists( $request, 'get_route' ) ? (string) $request->get_route() : '';
$method = is_object( $request ) && method_exists( $request, 'get_method' ) ? (string) $request->get_method() : '';

// Only act on the Payments providers endpoint used by the settings page (POST /wc-admin/settings/payments/providers).
if ( false === strpos( $route, '/wc-admin/settings/payments/providers' ) || 'POST' !== strtoupper( $method ) ) {
return $response;
}

$data = $response->get_data();
if ( ! is_array( $data ) || empty( $data['providers'] ) || ! is_array( $data['providers'] ) ) {
return $response;
}

$pricing_url = apply_filters( 'woo_alipay_pricing_url', 'https://woocn.com/product/woo-alipay.html#pricing' );
$about_url = apply_filters( 'woo_alipay_learn_more_url', 'https://woocn.com/document/woo-alipay' );
$terms_url = apply_filters( 'woo_alipay_terms_url', 'https://woocn.com/terms' );
$docs_url = apply_filters( 'woo_alipay_docs_url', 'https://woocn.com/document/woo-alipay' );
$support_url = apply_filters( 'woo_alipay_support_url', 'https://woocn.com/support' );

$target_ids = array( 'alipay', 'alipay_installment', 'alipay_facetopay' );

foreach ( $data['providers'] as $idx => $provider ) {
if ( ! is_array( $provider ) || empty( $provider['id'] ) || ! in_array( $provider['id'], $target_ids, true ) ) {
continue;
}

$links = array();
if ( isset( $provider['links'] ) && is_array( $provider['links'] ) ) {
$links = $provider['links'];
}

// Track existing link types to avoid duplicates.
$existing_types = array();
foreach ( $links as $link ) {
if ( is_array( $link ) && ! empty( $link['_type'] ) ) {
$existing_types[] = $link['_type'];
}
}

$to_add = array(
array( '_type' => 'pricing', 'url' => esc_url_raw( $pricing_url ) ),
array( '_type' => 'about', 'url' => esc_url_raw( $about_url ) ),
array( '_type' => 'terms', 'url' => esc_url_raw( $terms_url ) ),
array( '_type' => 'documentation', 'url' => esc_url_raw( $docs_url ) ),
array( '_type' => 'support', 'url' => esc_url_raw( $support_url ) ),
);

foreach ( $to_add as $entry ) {
if ( empty( $entry['_type'] ) || empty( $entry['url'] ) ) {
continue;
}
if ( in_array( $entry['_type'], $existing_types, true ) ) {
continue;
}
$links[] = $entry;
}

$data['providers'][ $idx ]['links'] = $links;
}

$response->set_data( $data );
} catch ( \Throwable $e ) {
// Fail-safe: do not block the response.
}

return $response;
}

public function render_admin_reconcile_page() {
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_die( __( '权限不足', 'woo-alipay' ) );
@ -248,16 +347,15 @@ class Woo_Alipay {
echo '</form></div>';
}

public function add_gateway( $methods ) {
public function add_gateway( $methods ) {
$methods[] = 'WC_Alipay';
$methods[] = 'WC_Alipay_Installment';
$methods[] = 'WC_Alipay_FaceToPay';

// Extension gateways are registered by their own plugins now.
return $methods;
}

public function plugin_edit_link( $links ) {
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout&section=woo_alipay' );
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout&section=alipay' );

return array_merge(
array(
@ -331,25 +429,12 @@ class Woo_Alipay {
if ( file_exists( WOO_ALIPAY_PLUGIN_PATH . 'inc/class-wc-alipay-blocks-support.php' ) ) {
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-wc-alipay-blocks-support.php';
}
if ( file_exists( WOO_ALIPAY_PLUGIN_PATH . 'inc/class-wc-alipay-installment-blocks-support.php' ) ) {
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-wc-alipay-installment-blocks-support.php';
}
if ( file_exists( WOO_ALIPAY_PLUGIN_PATH . 'inc/class-wc-alipay-facetopay-blocks-support.php' ) ) {
require_once WOO_ALIPAY_PLUGIN_PATH . 'inc/class-wc-alipay-facetopay-blocks-support.php';
}

// 注册主支付宝网关

// 注册主支付宝网关(扩展的 Blocks 支持由扩展自身注册)
if ( class_exists( 'WC_Alipay_Blocks_Support' ) ) {
$payment_method_registry->register( new WC_Alipay_Blocks_Support() );
}
// 注册花呗分期网关
if ( class_exists( 'WC_Alipay_Installment_Blocks_Support' ) ) {
$payment_method_registry->register( new WC_Alipay_Installment_Blocks_Support() );
}
// 注册当面付网关
if ( class_exists( 'WC_Alipay_FaceToPay_Blocks_Support' ) ) {
$payment_method_registry->register( new WC_Alipay_FaceToPay_Blocks_Support() );
}
}
);
}

View file

@ -1,66 +0,0 @@
<?php
/**
* 当面付二维码支付页面模板
*
* @var WC_Order $order 订单对象
* @var string $qr_code 二维码数据
* @var int $qrcode_size 二维码尺寸
* @var int $timeout 二维码有效期(秒)
*/

if (!defined('ABSPATH')) {
exit;
}
?>

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo('charset'); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow">
<title><?php echo esc_html__('扫码支付', 'woo-alipay'); ?> - <?php bloginfo('name'); ?></title>
<?php wp_head(); ?>
</head>
<body class="alipay-facetopay-page">

<div class="alipay-qrcode-container">
<div class="alipay-qrcode-header">
<h2><?php _e('请使用支付宝扫码支付', 'woo-alipay'); ?></h2>
<div class="order-info">
<?php echo sprintf(__('订单号: #%s', 'woo-alipay'), $order->get_id()); ?>
</div>
<div class="order-amount">
¥<?php echo number_format($order->get_total(), 2); ?>
</div>
</div>
<div class="alipay-qrcode-wrapper">
<div id="alipay-qrcode"
data-qrcode="<?php echo esc_attr($qr_code); ?>"
data-size="<?php echo esc_attr($qrcode_size); ?>"
data-order-id="<?php echo esc_attr($order->get_id()); ?>">
</div>
</div>
<div class="alipay-qrcode-tips">
<p><?php _e('请打开支付宝APP扫描上方二维码', 'woo-alipay'); ?></p>
<p><?php _e('二维码有效期内完成支付,支付完成后会自动跳转', 'woo-alipay'); ?></p>
<p class="alipay-deeplink">
<a class="button button-primary" href="<?php echo 'alipays://platformapi/startapp?saId=10000007&qrcode=' . rawurlencode($qr_code); ?>"><?php _e('在支付宝中打开', 'woo-alipay'); ?></a>
</p>
</div>
<div class="alipay-payment-status">
<span class="status-text"><?php _e('等待支付中...', 'woo-alipay'); ?></span>
</div>
<div class="alipay-qrcode-timer"></div>
</div>

<input type="hidden" id="alipay-facetopay-nonce" value="<?php echo wp_create_nonce('alipay_facetopay_query'); ?>">

<?php wp_footer(); ?>

</body>
</html>

View file

@ -1,6 +1,7 @@
/* global WooAlipay */
jQuery( document ).ready( function( $ ) {


$( '#woo-alipay-test-connection, #woo_alipay_test_connection' ).on( 'click', function( e ) {
e.preventDefault();


View file

@ -1,209 +0,0 @@
/**
* 当面付支付前端脚本
*/

(function($) {
'use strict';
let pollingTimer = null;
let timeoutTimer = null;
let remainingTime = 0;
let pollingAttempts = 0;
let refreshing = false;
const maxPollingAttempts = 100; // 最多轮询100次
const AlipayFaceToPay = {
init: function() {
const $qrcodeElement = $('#alipay-qrcode');
if ($qrcodeElement.length > 0 && typeof alipayFaceToPayParams !== 'undefined') {
const qrcodeData = $qrcodeElement.data('qrcode');
const qrcodeSize = parseInt($qrcodeElement.data('size'), 10) || 300;
const orderId = $qrcodeElement.data('order-id');
if (qrcodeData) {
this.generateQRCode(qrcodeData, qrcodeSize);
this.startPolling(orderId);
this.startTimeout();
}
}
},
generateQRCode: function(data, size) {
try {
new QRCode(document.getElementById('alipay-qrcode'), {
text: data,
width: size,
height: size,
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
});
} catch (error) {
console.error('生成二维码失败:', error);
this.showError('生成二维码失败,请刷新页面重试');
}
},
startPolling: function(orderId) {
const self = this;
const nonce = $('#alipay-facetopay-nonce').val();
pollingTimer = setInterval(function() {
if (pollingAttempts >= maxPollingAttempts) {
self.stopPolling();
return;
}
pollingAttempts++;
$.ajax({
url: alipayFaceToPayParams.ajax_url,
type: 'POST',
data: {
action: 'alipay_facetopay_query',
order_id: orderId,
nonce: nonce
},
success: function(response) {
if (response.success && response.data.status === 'paid') {
self.stopPolling();
self.showSuccess();
setTimeout(function() {
window.location.href = response.data.redirect_url;
}, 1500);
}
},
error: function(xhr, status, error) {
console.error('查询支付状态失败:', error);
}
});
}, alipayFaceToPayParams.polling_interval || 2000);
},
stopPolling: function() {
if (pollingTimer) {
clearInterval(pollingTimer);
pollingTimer = null;
}
},
startTimeout: function() {
const self = this;
remainingTime = alipayFaceToPayParams.timeout || 120;
this.updateTimer();
timeoutTimer = setInterval(function() {
remainingTime--;
self.updateTimer();

// 即将过期时自动刷新二维码
if (remainingTime <= 5 && !refreshing) {
self.refreshQRCode();
}
if (remainingTime <= 0) {
self.stopPolling();
clearInterval(timeoutTimer);
self.showExpired();
}
}, 1000);
},
updateTimer: function() {
const $timer = $('.alipay-qrcode-timer');
if ($timer.length > 0) {
const minutes = Math.floor(remainingTime / 60);
const seconds = remainingTime % 60;
const timeStr = minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
$timer.text('剩余时间: ' + timeStr);
if (remainingTime <= 30) {
$timer.addClass('warning');
}
}
},
showSuccess: function() {
const $status = $('.alipay-payment-status');
$status.removeClass('error').addClass('success');
$status.html(
'<span class="status-icon">✓</span>' +
'<span class="status-text">支付成功!正在跳转...</span>'
);
},
showError: function(message) {
const $status = $('.alipay-payment-status');
$status.removeClass('success').addClass('error');
$status.html(
'<span class="status-icon">✕</span>' +
'<span class="status-text">' + message + '</span>'
);
},
refreshQRCode: function() {
const self = this;
if (refreshing) return;
const $qrcodeElement = $('#alipay-qrcode');
const orderId = $qrcodeElement.data('order-id');
const nonce = $('#alipay-facetopay-nonce').val();
refreshing = true;
$.ajax({
url: alipayFaceToPayParams.ajax_url,
type: 'POST',
data: {
action: 'alipay_facetopay_refresh_qrcode',
order_id: orderId,
nonce: nonce
},
success: function(response) {
refreshing = false;
if (response.success && response.data.qr_code) {
// 重新渲染二维码
$('#alipay-qrcode').empty();
const size = parseInt($qrcodeElement.data('size'), 10) || 300;
$('#alipay-qrcode').attr('data-qrcode', response.data.qr_code);
AlipayFaceToPay.generateQRCode(response.data.qr_code, size);
// 重置计时
remainingTime = parseInt(response.data.timeout || 120, 10);
}
},
error: function() { refreshing = false; }
});
},
showExpired: function() {
const $container = $('.alipay-qrcode-container');
$container.html(
'<div class="alipay-qrcode-expired">' +
'<div class="expired-icon">⏱</div>' +
'<div class="expired-text">二维码已过期</div>' +
'<button class="refresh-button" onclick="location.reload()">刷新页面</button>' +
'</div>'
);
}
};
$(document).ready(function() {
AlipayFaceToPay.init();
});
// 页面卸载时停止轮询
$(window).on('beforeunload', function() {
if (pollingTimer) {
clearInterval(pollingTimer);
}
if (timeoutTimer) {
clearInterval(timeoutTimer);
}
});
})(jQuery);

View file

@ -1,38 +0,0 @@
/**
* 花呗分期支付前端脚本
*/

(function($) {
'use strict';
$(document).ready(function() {
// 确保至少选中一个分期选项
const $installmentRadios = $('input[name="alipay_installment_period"]');
if ($installmentRadios.length > 0) {
// 如果没有任何选中的,选中第一个
if ($installmentRadios.filter(':checked').length === 0) {
$installmentRadios.first().prop('checked', true);
}
// 添加点击动画效果
$installmentRadios.on('change', function() {
$(this).closest('label').addClass('period-selected');
$installmentRadios.not(this).closest('label').removeClass('period-selected');
});
}
// 在提交订单前验证是否选择了分期期数
$('form.checkout').on('checkout_place_order_alipay_installment', function() {
const $selectedPeriod = $('input[name="alipay_installment_period"]:checked');
if ($selectedPeriod.length === 0) {
alert('请选择分期期数');
return false;
}
return true;
});
});
})(jQuery);

View file

@ -1,9 +0,0 @@
<?php return array(
'dependencies' => array(
'wc-blocks-registry',
'wp-element',
'wp-html-entities',
'wp-i18n',
),
'version' => '3.1.0',
);

View file

@ -1,81 +0,0 @@
(function(){
const { registerPaymentMethod } = window.wc.wcBlocksRegistry;
const { createElement } = window.wp.element;
const { __ } = window.wp.i18n;
const { decodeEntities } = window.wp.htmlEntities;

const settings = window.wc.wcSettings.getSetting( 'alipay_facetopay_data', {} );
const defaultLabel = __( '支付宝扫码支付', 'woo-alipay' );
const defaultDescription = __( '使用支付宝扫描二维码完成支付', 'woo-alipay' );

const Label = ( props ) => {
const { PaymentMethodLabel } = props.components;
const iconElement = settings.icon ? createElement( 'img', {
src: settings.icon,
alt: decodeEntities( settings.title || defaultLabel ),
style: {
width: '24px',
height: '24px',
marginRight: '8px',
verticalAlign: 'middle'
}
} ) : null;
return createElement( 'div', {
style: { display: 'flex', alignItems: 'center' }
}, [
iconElement,
createElement( PaymentMethodLabel, {
text: decodeEntities( settings.title || defaultLabel ),
key: 'label'
} )
] );
};

const Content = () => {
return createElement( 'div', {
style: { padding: '10px 0' }
}, [
createElement( 'p', {
key: 'description',
style: { marginBottom: '8px' }
}, decodeEntities( settings.description || defaultDescription ) ),
createElement( 'div', {
key: 'qr-info',
style: {
padding: '10px',
background: '#f0f7ff',
border: '1px solid #d6e4ff',
borderRadius: '4px',
fontSize: '13px',
color: '#096dd9'
}
}, [
createElement( 'p', {
key: 'tip1',
style: { margin: '4px 0' }
}, __( '点击下单后会显示支付二维码', 'woo-alipay' ) ),
createElement( 'p', {
key: 'tip2',
style: { margin: '4px 0' }
}, __( '请使用支付宝APP扫描二维码完成支付', 'woo-alipay' ) )
])
]);
};

const alipayFaceToPayPaymentMethod = {
name: 'alipay_facetopay',
label: createElement( Label ),
content: createElement( Content ),
edit: createElement( Content ),
canMakePayment: () => true,
ariaLabel: decodeEntities( settings.title || defaultLabel ),
supports: {
features: settings?.supports ?? ['products'],
},
};

registerPaymentMethod( alipayFaceToPayPaymentMethod );
})();

View file

@ -1,9 +0,0 @@
<?php return array(
'dependencies' => array(
'wc-blocks-registry',
'wp-element',
'wp-html-entities',
'wp-i18n',
),
'version' => '3.1.0',
);

View file

@ -1,169 +0,0 @@
(function(){
const { registerPaymentMethod } = window.wc.wcBlocksRegistry;
const { createElement, useState, useEffect } = window.wp.element;
const { __ } = window.wp.i18n;
const { decodeEntities } = window.wp.htmlEntities;

const settings = window.wc.wcSettings.getSetting( 'alipay_installment_data', {} );
const defaultLabel = __( '支付宝花呗分期', 'woo-alipay' );
const defaultDescription = __( '使用支付宝花呗分期付款支持3期、6期、12期免息或低息分期。', 'woo-alipay' );

const Label = ( props ) => {
const { PaymentMethodLabel } = props.components;
const iconElement = settings.icon ? createElement( 'img', {
src: settings.icon,
alt: decodeEntities( settings.title || defaultLabel ),
style: {
width: '24px',
height: '24px',
marginRight: '8px',
verticalAlign: 'middle'
}
} ) : null;
return createElement( 'div', {
style: { display: 'flex', alignItems: 'center' }
}, [
iconElement,
createElement( PaymentMethodLabel, {
text: decodeEntities( settings.title || defaultLabel ),
key: 'label'
} )
] );
};

const Content = ( props ) => {
// 检查是否满足最小金额要求
const meetsMinAmount = settings.meetsMinAmount || false;
const minAmount = settings.minAmount || 100;
const cartTotal = settings.cartTotal || 0;
const availablePeriods = settings.availablePeriods || ['3', '6', '12'];
const defaultPeriod = settings.defaultPeriod || '3';

const [ selectedPeriod, setSelectedPeriod ] = useState( String(defaultPeriod) );

// 将选择的分期数传递到服务端Store API -> payment_data
useEffect( () => {
if ( ! props?.eventRegistration ) return;
const unsubscribe = props.eventRegistration.onPaymentSetup( () => {
return {
type: 'success',
paymentMethodData: {
alipay_installment_period: selectedPeriod,
},
};
} );
return () => {
if ( typeof unsubscribe === 'function' ) unsubscribe();
};
}, [ selectedPeriod ] );
// 如果不满足最小金额,显示提示
if (!meetsMinAmount) {
return createElement( 'div', {
style: {
padding: '10px',
background: '#fff3cd',
border: '1px solid #ffc107',
borderRadius: '4px',
color: '#856404',
marginTop: '10px'
}
}, __( '订单金额需满 ¥' + minAmount + ' 才能使用花呗分期', 'woo-alipay' ) );
}
return createElement( 'div', {
style: { padding: '10px 0' }
}, [
createElement( 'p', {
key: 'description',
style: { marginBottom: '15px' }
}, decodeEntities( settings.description || defaultDescription ) ),
createElement( 'p', {
key: 'fee-note',
style: { margin: '6px 0', fontSize: '12px', color: '#666' }
}, settings.feePayer === 'seller' ? __( '免息分期(手续费由商家承担)', 'woo-alipay' ) : __( '可能产生分期手续费,以支付宝支付页面为准', 'woo-alipay' ) ),
createElement( 'div', {
key: 'period-info',
style: {
padding: '12px',
background: '#f9f9f9',
border: '1px solid #e0e0e0',
borderRadius: '4px',
marginTop: '10px'
}
}, [
createElement( 'p', {
key: 'title',
style: {
fontWeight: '600',
marginBottom: '8px',
fontSize: '14px'
}
}, __( '选择分期期数:', 'woo-alipay' ) ),
createElement( 'div', {
key: 'periods',
style: {
margin: '0',
padding: '0',
display: 'grid',
gap: '6px'
}
}, availablePeriods.map(period => {
const monthlyAmount = (cartTotal / parseInt(period)).toFixed(2);
const id = 'alipay-installment-' + period;
return createElement( 'label', {
key: period,
htmlFor: id,
style: { display: 'flex', alignItems: 'center', gap: '8px', fontSize: '13px' }
}, [
createElement( 'input', {
id,
type: 'radio',
name: 'alipay_installment_period',
value: String(period),
checked: String(selectedPeriod) === String(period),
onChange: () => setSelectedPeriod(String(period))
} ),
createElement( 'span', { key: 'label-' + period }, [
period + ' 期(每期 ¥' + monthlyAmount,
(settings.feePayer === 'seller' && settings.showInterestFreeBadge) ? createElement('span', { key: 'free-'+period, className: 'alipay-badge alipay-badge--free', style: { marginLeft: '4px' } }, __('免息', 'woo-alipay')) : null,
''
] )
] );
}) )
]),
createElement( 'p', {
key: 'note',
style: {
marginTop: '10px',
fontSize: '12px',
color: '#666'
}
}, __( '在支付页面将可以选择具体的分期期数', 'woo-alipay' ) )
]);
};

const alipayInstallmentPaymentMethod = {
name: 'alipay_installment',
paymentMethodId: 'alipay_installment',
label: createElement( Label ),
content: createElement( Content ),
edit: createElement( Content ),
canMakePayment: () => {
const behavior = settings.insufficientBehavior || 'hide';
const meets = !!settings.meetsMinAmount;
if ( behavior === 'hide' && !meets ) return false;
return true;
},
ariaLabel: decodeEntities( settings.title || defaultLabel ),
supports: {
features: settings?.supports ?? ['products'],
},
};

registerPaymentMethod( alipayInstallmentPaymentMethod );
})();

View file

@ -1,21 +0,0 @@
# The MIT License (MIT)

Copyright (c) 2016-2019 Riku Särkinen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,29 +0,0 @@
{
"name": "adbario/php-dot-notation",
"description": "PHP dot notation access to arrays",
"keywords": ["dotnotation", "arrayaccess"],
"homepage": "https://github.com/adbario/php-dot-notation",
"license": "MIT",
"authors": [
{
"name": "Riku Särkinen",
"email": "riku@adbar.io"
}
],
"require": {
"php": "^5.5 || ^7.0 || ^8.0",
"ext-json": "*"
},
"require-dev": {
"phpunit/phpunit": "^4.8|^5.7|^6.6|^7.5|^8.5|^9.5",
"squizlabs/php_codesniffer": "^3.6"
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Adbar\\": "src"
}
}
}

View file

@ -1,623 +0,0 @@
<?php
/**
* Dot - PHP dot notation access to arrays
*
* @author Riku Särkinen <riku@adbar.io>
* @link https://github.com/adbario/php-dot-notation
* @license https://github.com/adbario/php-dot-notation/blob/2.x/LICENSE.md (MIT License)
*/
namespace Adbar;

use Countable;
use ArrayAccess;
use ArrayIterator;
use JsonSerializable;
use IteratorAggregate;

/**
* Dot
*
* This class provides a dot notation access and helper functions for
* working with arrays of data. Inspired by Laravel Collection.
*/
class Dot implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
{
/**
* The stored items
*
* @var array
*/
protected $items = [];


/**
* The delimiter (alternative to a '.') to be used.
*
* @var string
*/
protected $delimiter = '.';


/**
* Create a new Dot instance
*
* @param mixed $items
* @param string $delimiter
*/
public function __construct($items = [], $delimiter = '.')
{
$this->items = $this->getArrayItems($items);
$this->delimiter = strlen($delimiter) ? $delimiter : '.';
}

/**
* Set a given key / value pair or pairs
* if the key doesn't exist already
*
* @param array|int|string $keys
* @param mixed $value
*/
public function add($keys, $value = null)
{
if (is_array($keys)) {
foreach ($keys as $key => $value) {
$this->add($key, $value);
}
} elseif (is_null($this->get($keys))) {
$this->set($keys, $value);
}
}

/**
* Return all the stored items
*
* @return array
*/
public function all()
{
return $this->items;
}

/**
* Delete the contents of a given key or keys
*
* @param array|int|string|null $keys
*/
public function clear($keys = null)
{
if (is_null($keys)) {
$this->items = [];

return;
}

$keys = (array) $keys;

foreach ($keys as $key) {
$this->set($key, []);
}
}

/**
* Delete the given key or keys
*
* @param array|int|string $keys
*/
public function delete($keys)
{
$keys = (array) $keys;

foreach ($keys as $key) {
if ($this->exists($this->items, $key)) {
unset($this->items[$key]);

continue;
}

$items = &$this->items;
$segments = explode($this->delimiter, $key);
$lastSegment = array_pop($segments);

foreach ($segments as $segment) {
if (!isset($items[$segment]) || !is_array($items[$segment])) {
continue 2;
}

$items = &$items[$segment];
}

unset($items[$lastSegment]);
}
}

/**
* Checks if the given key exists in the provided array.
*
* @param array $array Array to validate
* @param int|string $key The key to look for
*
* @return bool
*/
protected function exists($array, $key)
{
return array_key_exists($key, $array);
}

/**
* Flatten an array with the given character as a key delimiter
*
* @param string $delimiter
* @param array|null $items
* @param string $prepend
* @return array
*/
public function flatten($delimiter = '.', $items = null, $prepend = '')
{
$flatten = [];

if (is_null($items)) {
$items = $this->items;
}

if (!func_num_args()) {
$delimiter = $this->delimiter;
}

foreach ($items as $key => $value) {
if (is_array($value) && !empty($value)) {
$flatten = array_merge(
$flatten,
$this->flatten($delimiter, $value, $prepend.$key.$delimiter)
);
} else {
$flatten[$prepend.$key] = $value;
}
}

return $flatten;
}

/**
* Return the value of a given key
*
* @param int|string|null $key
* @param mixed $default
* @return mixed
*/
public function get($key = null, $default = null)
{
if (is_null($key)) {
return $this->items;
}

if ($this->exists($this->items, $key)) {
return $this->items[$key];
}

if (strpos($key, $this->delimiter) === false) {
return $default;
}

$items = $this->items;

foreach (explode($this->delimiter, $key) as $segment) {
if (!is_array($items) || !$this->exists($items, $segment)) {
return $default;
}

$items = &$items[$segment];
}

return $items;
}

/**
* Return the given items as an array
*
* @param mixed $items
* @return array
*/
protected function getArrayItems($items)
{
if (is_array($items)) {
return $items;
} elseif ($items instanceof self) {
return $items->all();
}

return (array) $items;
}

/**
* Check if a given key or keys exists
*
* @param array|int|string $keys
* @return bool
*/
public function has($keys)
{
$keys = (array) $keys;

if (!$this->items || $keys === []) {
return false;
}

foreach ($keys as $key) {
$items = $this->items;

if ($this->exists($items, $key)) {
continue;
}

foreach (explode($this->delimiter, $key) as $segment) {
if (!is_array($items) || !$this->exists($items, $segment)) {
return false;
}

$items = $items[$segment];
}
}

return true;
}

/**
* Check if a given key or keys are empty
*
* @param array|int|string|null $keys
* @return bool
*/
public function isEmpty($keys = null)
{
if (is_null($keys)) {
return empty($this->items);
}

$keys = (array) $keys;

foreach ($keys as $key) {
if (!empty($this->get($key))) {
return false;
}
}

return true;
}

/**
* Merge a given array or a Dot object with the given key
* or with the whole Dot object
*
* @param array|string|self $key
* @param array|self $value
*/
public function merge($key, $value = [])
{
if (is_array($key)) {
$this->items = array_merge($this->items, $key);
} elseif (is_string($key)) {
$items = (array) $this->get($key);
$value = array_merge($items, $this->getArrayItems($value));

$this->set($key, $value);
} elseif ($key instanceof self) {
$this->items = array_merge($this->items, $key->all());
}
}

/**
* Recursively merge a given array or a Dot object with the given key
* or with the whole Dot object.
*
* Duplicate keys are converted to arrays.
*
* @param array|string|self $key
* @param array|self $value
*/
public function mergeRecursive($key, $value = [])
{
if (is_array($key)) {
$this->items = array_merge_recursive($this->items, $key);
} elseif (is_string($key)) {
$items = (array) $this->get($key);
$value = array_merge_recursive($items, $this->getArrayItems($value));

$this->set($key, $value);
} elseif ($key instanceof self) {
$this->items = array_merge_recursive($this->items, $key->all());
}
}

/**
* Recursively merge a given array or a Dot object with the given key
* or with the whole Dot object.
*
* Instead of converting duplicate keys to arrays, the value from
* given array will replace the value in Dot object.
*
* @param array|string|self $key
* @param array|self $value
*/
public function mergeRecursiveDistinct($key, $value = [])
{
if (is_array($key)) {
$this->items = $this->arrayMergeRecursiveDistinct($this->items, $key);
} elseif (is_string($key)) {
$items = (array) $this->get($key);
$value = $this->arrayMergeRecursiveDistinct($items, $this->getArrayItems($value));

$this->set($key, $value);
} elseif ($key instanceof self) {
$this->items = $this->arrayMergeRecursiveDistinct($this->items, $key->all());
}
}

/**
* Merges two arrays recursively. In contrast to array_merge_recursive,
* duplicate keys are not converted to arrays but rather overwrite the
* value in the first array with the duplicate value in the second array.
*
* @param array $array1 Initial array to merge
* @param array $array2 Array to recursively merge
* @return array
*/
protected function arrayMergeRecursiveDistinct(array $array1, array $array2)
{
$merged = &$array1;

foreach ($array2 as $key => $value) {
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
$merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value);
} else {
$merged[$key] = $value;
}
}

return $merged;
}

/**
* Return the value of a given key and
* delete the key
*
* @param int|string|null $key
* @param mixed $default
* @return mixed
*/
public function pull($key = null, $default = null)
{
if (is_null($key)) {
$value = $this->all();
$this->clear();

return $value;
}

$value = $this->get($key, $default);
$this->delete($key);

return $value;
}

/**
* Push a given value to the end of the array
* in a given key
*
* @param mixed $key
* @param mixed $value
*/
public function push($key, $value = null)
{
if (is_null($value)) {
$this->items[] = $key;

return;
}

$items = $this->get($key);

if (is_array($items) || is_null($items)) {
$items[] = $value;
$this->set($key, $items);
}
}

/**
* Replace all values or values within the given key
* with an array or Dot object
*
* @param array|string|self $key
* @param array|self $value
*/
public function replace($key, $value = [])
{
if (is_array($key)) {
$this->items = array_replace($this->items, $key);
} elseif (is_string($key)) {
$items = (array) $this->get($key);
$value = array_replace($items, $this->getArrayItems($value));

$this->set($key, $value);
} elseif ($key instanceof self) {
$this->items = array_replace($this->items, $key->all());
}
}

/**
* Set a given key / value pair or pairs
*
* @param array|int|string $keys
* @param mixed $value
*/
public function set($keys, $value = null)
{
if (is_array($keys)) {
foreach ($keys as $key => $value) {
$this->set($key, $value);
}

return;
}

$items = &$this->items;

foreach (explode($this->delimiter, $keys) as $key) {
if (!isset($items[$key]) || !is_array($items[$key])) {
$items[$key] = [];
}

$items = &$items[$key];
}

$items = $value;
}

/**
* Replace all items with a given array
*
* @param mixed $items
*/
public function setArray($items)
{
$this->items = $this->getArrayItems($items);
}

/**
* Replace all items with a given array as a reference
*
* @param array $items
*/
public function setReference(array &$items)
{
$this->items = &$items;
}

/**
* Return the value of a given key or all the values as JSON
*
* @param mixed $key
* @param int $options
* @return string
*/
public function toJson($key = null, $options = 0)
{
if (is_string($key)) {
return json_encode($this->get($key), $options);
}

$options = $key === null ? 0 : $key;

return json_encode($this->items, $options);
}

/*
* --------------------------------------------------------------
* ArrayAccess interface
* --------------------------------------------------------------
*/

/**
* Check if a given key exists
*
* @param int|string $key
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($key)
{
return $this->has($key);
}

/**
* Return the value of a given key
*
* @param int|string $key
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($key)
{
return $this->get($key);
}

/**
* Set a given value to the given key
*
* @param int|string|null $key
* @param mixed $value
*/
#[\ReturnTypeWillChange]
public function offsetSet($key, $value)
{
if (is_null($key)) {
$this->items[] = $value;

return;
}

$this->set($key, $value);
}

/**
* Delete the given key
*
* @param int|string $key
*/
#[\ReturnTypeWillChange]
public function offsetUnset($key)
{
$this->delete($key);
}

/*
* --------------------------------------------------------------
* Countable interface
* --------------------------------------------------------------
*/

/**
* Return the number of items in a given key
*
* @param int|string|null $key
* @return int
*/
#[\ReturnTypeWillChange]
public function count($key = null)
{
return count($this->get($key));
}

/*
* --------------------------------------------------------------
* IteratorAggregate interface
* --------------------------------------------------------------
*/

/**
* Get an iterator for the stored items
*
* @return \ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new ArrayIterator($this->items);
}

/*
* --------------------------------------------------------------
* JsonSerializable interface
* --------------------------------------------------------------
*/

/**
* Return items for JSON serialization
*
* @return array
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->items;
}
}

View file

@ -1,24 +0,0 @@
<?php
/**
* Dot - PHP dot notation access to arrays
*
* @author Riku Särkinen <riku@adbar.io>
* @link https://github.com/adbario/php-dot-notation
* @license https://github.com/adbario/php-dot-notation/blob/2.x/LICENSE.md (MIT License)
*/

use Adbar\Dot;

if (! function_exists('dot')) {
/**
* Create a new Dot object with the given items and optional delimiter
*
* @param mixed $items
* @param string $delimiter
* @return \Adbar\Dot
*/
function dot($items, $delimiter = '.')
{
return new Dot($items, $delimiter);
}
}

View file

@ -1,12 +0,0 @@
composer.phar
/vendor/

# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
composer.lock

.idea
.DS_Store

cache/
*.cache

View file

@ -1,65 +0,0 @@
<?php
/*
* This document has been generated with
* https://mlocati.github.io/php-cs-fixer-configurator/#version:2.15|configurator
* you can change this configuration by importing this file.
*/

return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setIndent(' ')
->setRules([
'@PSR2' => true,
'@PhpCsFixer' => true,
'@Symfony:risky' => true,
'concat_space' => ['spacing' => 'one'],
'array_syntax' => ['syntax' => 'short'],
'array_indentation' => true,
'combine_consecutive_unsets' => true,
'method_separation' => true,
'single_quote' => true,
'declare_equal_normalize' => true,
'function_typehint_space' => true,
'hash_to_slash_comment' => true,
'include' => true,
'lowercase_cast' => true,
'no_multiline_whitespace_before_semicolons' => true,
'no_leading_import_slash' => true,
'no_multiline_whitespace_around_double_arrow' => true,
'no_spaces_around_offset' => true,
'no_unneeded_control_parentheses' => true,
'no_unused_imports' => true,
'no_whitespace_before_comma_in_array' => true,
'no_whitespace_in_blank_line' => true,
'object_operator_without_whitespace' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => true,
'space_after_semicolon' => true,
'standardize_not_equals' => true,
'ternary_operator_spaces' => true,
'trailing_comma_in_multiline_array' => true,
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'whitespace_after_comma_in_array' => true,
'no_extra_consecutive_blank_lines' => [
'curly_brace_block',
'extra',
'parenthesis_brace_block',
'square_brace_block',
'throw',
'use',
],
'binary_operator_spaces' => [
'align_double_arrow' => true,
'align_equals' => true,
],
'braces' => [
'allow_single_line_closure' => true,
],
])
->setFinder(
PhpCsFixer\Finder::create()
->exclude('vendor')
->exclude('tests')
->in(__DIR__)
);

View file

@ -1,31 +0,0 @@
English | [简体中文](README-CN.md)

![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg)

## Alibaba Cloud Tea File Library for PHP

## Installation

### Composer

```bash
composer require alibabacloud/tea-fileform
```

## Issues

[Opening an Issue](https://github.com/aliyun/tea-fileform/issues/new), Issues not conforming to the guidelines may be closed immediately.

## Changelog

Detailed changes for each release are documented in the [release notes](./ChangeLog.txt).

## References

* [Latest Release](https://github.com/aliyun/tea-fileform)

## License

[Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0)

Copyright (c) 2009-present, Alibaba Cloud All rights reserved.

View file

@ -1,31 +0,0 @@
[English](README.md) | 简体中文

![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg)

## Alibaba Cloud Tea File Library for PHP

## 安装

### Composer

```bash
composer require alibabacloud/tea-fileform
```

## 问题

[提交 Issue](https://github.com/aliyun/tea-fileform/issues/new),不符合指南的问题可能会立即关闭。

## 发行说明

每个版本的详细更改记录在[发行说明](./ChangeLog.txt)中。

## 相关

* [最新源码](https://github.com/aliyun/tea-fileform)

## 许可证

[Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0)

Copyright (c) 2009-present, Alibaba Cloud All rights reserved.

View file

@ -1,44 +0,0 @@
{
"name": "alibabacloud/tea-fileform",
"description": "Alibaba Cloud Tea File Library for PHP",
"type": "library",
"license": "Apache-2.0",
"authors": [
{
"name": "Alibaba Cloud SDK",
"email": "sdk-team@alibabacloud.com"
}
],
"require": {
"php": ">5.5",
"alibabacloud/tea": "^3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5.4.3"
},
"autoload": {
"psr-4": {
"AlibabaCloud\\Tea\\FileForm\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"AlibabaCloud\\Tea\\FileForm\\Tests\\": "tests"
}
},
"scripts": {
"fixer": "php-cs-fixer fix ./",
"test": [
"@clearCache",
"phpunit --colors=always"
],
"clearCache": "rm -rf cache/*"
},
"config": {
"sort-packages": true,
"preferred-install": "dist",
"optimize-autoloader": true
},
"prefer-stable": true,
"minimum-stability": "dev"
}

View file

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="./tests/bootstrap.php" colors="true" processIsolation="false" stopOnFailure="false"
convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true"
testSuiteLoaderFile="phpunit/src/Runner/StandardTestSuiteLoader.php">

<testsuites>
<testsuite name="All">
<directory>tests</directory>
</testsuite>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
</testsuites>

<groups>
<exclude>
<group>integration</group>
</exclude>
</groups>

<logging>
<log type="coverage-html" target="cache/coverage" lowUpperBound="35" highLowerBound="70"/>
<log type="coverage-clover" target="cache/coverage.clover"/>
</logging>


<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>

View file

@ -1,16 +0,0 @@
<?php

namespace AlibabaCloud\Tea\FileForm;

class FileForm
{
public static function getBoundary()
{
return (string) (mt_rand(10000000000000, 99999999999999));
}

public static function toFileForm($map, $boundary)
{
return new FileFormStream($map, $boundary);
}
}

View file

@ -1,22 +0,0 @@
<?php

namespace AlibabaCloud\Tea\FileForm\FileForm;

use AlibabaCloud\Tea\Model;

class FileField extends Model
{
public $filename;
public $contentType;
public $content;

public function __construct($config = [])
{
$this->_required = [
'filename' => true,
'contentType' => true,
'content' => true,
];
parent::__construct($config);
}
}

View file

@ -1,321 +0,0 @@
<?php

namespace AlibabaCloud\Tea\FileForm;

use AlibabaCloud\Tea\FileForm\FileForm\FileField;
use GuzzleHttp\Psr7\Stream;
use Psr\Http\Message\StreamInterface;

/**
* @internal
* @coversNothing
*/
class FileFormStream implements StreamInterface
{
/**
* @var resource
*/
private $stream;
private $index = 0;
private $form = [];
private $boundary = '';
private $streaming = false;
private $keys = [];

/**
* @var Stream
*/
private $currStream;

private $size;
private $uri;
private $seekable;
private $readable = true;
private $writable = true;

public function __construct($map, $boundary)
{
$this->stream = fopen('php://memory', 'a+');
$this->form = $map;
$this->boundary = $boundary;
$this->keys = array_keys($map);
do {
$read = $this->readForm(1024);
} while (null !== $read);
$meta = stream_get_meta_data($this->stream);
$this->seekable = $meta['seekable'];
$this->uri = $this->getMetadata('uri');
$this->seek(0);
$this->seek(0);
}

/**
* Closes the stream when the destructed.
*/
public function __destruct()
{
$this->close();
}

public function __toString()
{
try {
$this->seek(0);

return (string) stream_get_contents($this->stream);
} catch (\Exception $e) {
return '';
}
}

/**
* @param int $length
*
* @return false|int|string
*/
public function readForm($length)
{
if ($this->streaming) {
if (null !== $this->currStream) {
// @var string $content
$content = $this->currStream->read($length);
if (false !== $content && '' !== $content) {
fwrite($this->stream, $content);

return $content;
}

return $this->next("\r\n");
}

return $this->next();
}
$keysCount = \count($this->keys);
if ($this->index > $keysCount) {
return null;
}
if ($keysCount > 0) {
if ($this->index < $keysCount) {
$this->streaming = true;

$name = $this->keys[$this->index];
$field = $this->form[$name];
if (!empty($field) && $field instanceof FileField) {
if (!empty($field->content)) {
$this->currStream = $field->content;

$str = '--' . $this->boundary . "\r\n" .
'Content-Disposition: form-data; name="' . $name . '"; filename="' . $field->filename . "\"\r\n" .
'Content-Type: ' . $field->contentType . "\r\n\r\n";
$this->write($str);

return $str;
}

return $this->next();
}
$val = $field;
$str = '--' . $this->boundary . "\r\n" .
'Content-Disposition: form-data; name="' . $name . "\"\r\n\r\n" .
$val . "\r\n";
fwrite($this->stream, $str);

return $str;
}
if ($this->index == $keysCount) {
return $this->next('--' . $this->boundary . "--\r\n");
}

return null;
}

return null;
}

public function getContents()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}

$contents = stream_get_contents($this->stream);

if (false === $contents) {
throw new \RuntimeException('Unable to read stream contents');
}

return $contents;
}

public function close()
{
if (isset($this->stream)) {
if (\is_resource($this->stream)) {
fclose($this->stream);
}
$this->detach();
}
}

public function detach()
{
if (!isset($this->stream)) {
return null;
}

$result = $this->stream;
unset($this->stream);
$this->size = $this->uri = null;

return $result;
}

public function getSize()
{
if (null !== $this->size) {
return $this->size;
}

if (!isset($this->stream)) {
return null;
}

// Clear the stat cache if the stream has a URI
if ($this->uri) {
clearstatcache(true, $this->uri);
}

$stats = fstat($this->stream);
if (isset($stats['size'])) {
$this->size = $stats['size'];

return $this->size;
}

return null;
}

public function isReadable()
{
return $this->readable;
}

public function isWritable()
{
return $this->writable;
}

public function isSeekable()
{
return $this->seekable;
}

public function eof()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}

return feof($this->stream);
}

public function tell()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}

$result = ftell($this->stream);

if (false === $result) {
throw new \RuntimeException('Unable to determine stream position');
}

return $result;
}

public function rewind()
{
$this->seek(0);
}

public function seek($offset, $whence = SEEK_SET)
{
$whence = (int) $whence;

if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->seekable) {
throw new \RuntimeException('Stream is not seekable');
}
if (-1 === fseek($this->stream, $offset, $whence)) {
throw new \RuntimeException('Unable to seek to stream position ' . $offset . ' with whence ' . var_export($whence, true));
}
}

public function read($length)
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->readable) {
throw new \RuntimeException('Cannot read from non-readable stream');
}
if ($length < 0) {
throw new \RuntimeException('Length parameter cannot be negative');
}

if (0 === $length) {
return '';
}

$string = fread($this->stream, $length);
if (false === $string) {
throw new \RuntimeException('Unable to read from stream');
}

return $string;
}

public function write($string)
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
if (!$this->writable) {
throw new \RuntimeException('Cannot write to a non-writable stream');
}

// We can't know the size after writing anything
$this->size = null;
$result = fwrite($this->stream, $string);

if (false === $result) {
throw new \RuntimeException('Unable to write to stream');
}

return $result;
}

public function getMetadata($key = null)
{
if (!isset($this->stream)) {
return $key ? null : [];
}

$meta = stream_get_meta_data($this->stream);

return isset($meta[$key]) ? $meta[$key] : null;
}

private function next($endStr = '')
{
$this->streaming = false;
++$this->index;
$this->write($endStr);
$this->currStream = null;

return $endStr;
}
}

View file

@ -1,81 +0,0 @@
<?php

namespace AlibabaCloud\Tea\FileForm\Tests;

use AlibabaCloud\Tea\FileForm\FileForm;
use AlibabaCloud\Tea\FileForm\FileForm\FileField;
use AlibabaCloud\Tea\FileForm\FileFormStream;
use GuzzleHttp\Psr7\Stream;
use PHPUnit\Framework\TestCase;

/**
* @internal
* @coversNothing
*/
class FileFormTest extends TestCase
{
public function testFileFromStream()
{
$boundary = FileForm::getBoundary();
$stream = FileForm::toFileForm([], $boundary);
$this->assertTrue($stream instanceof FileFormStream);
$stream->write($boundary);
$this->assertTrue(\strlen($boundary) === $stream->getSize());
}

public function testSet()
{
$fileField = new FileField([
'filename' => 'fake filename',
'contentType' => 'content type',
'content' => null,
]);

$this->assertEquals('fake filename', $fileField->filename);
$this->assertEquals('content type', $fileField->contentType);
}

public function testRead()
{
$fileField = new FileField();
$fileField->filename = 'haveContent';
$fileField->contentType = 'contentType';
$fileField->content = new Stream(fopen('data://text/plain;base64,' . base64_encode('This is file test. This sentence must be long'), 'r'));

$fileFieldNoContent = new FileField();
$fileFieldNoContent->filename = 'noContent';
$fileFieldNoContent->contentType = 'contentType';
$fileFieldNoContent->content = null;

$map = [
'key' => 'value',
'testKey' => 'testValue',
'haveFile' => $fileField,
'noFile' => $fileFieldNoContent,
];

$stream = FileForm::toFileForm($map, 'testBoundary');

$result = $stream->getContents();
$target = "--testBoundary\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\nvalue\r\n--testBoundary\r\nContent-Disposition: form-data; name=\"testKey\"\r\n\r\ntestValue\r\n--testBoundary\r\nContent-Disposition: form-data; name=\"haveFile\"; filename=\"haveContent\"\r\nContent-Type: contentType\r\n\r\nThis is file test. This sentence must be long\r\n--testBoundary--\r\n";

$this->assertEquals($target, $result);
}

public function testReadFile()
{
$fileField = new FileField();
$fileField->filename = 'composer.json';
$fileField->contentType = 'application/json';
$fileField->content = new Stream(fopen(__DIR__ . '/../composer.json', 'r'));
$map = [
'name' => 'json_file',
'type' => 'application/json',
'json_file' => $fileField,
];

$boundary = FileForm::getBoundary();
$fileStream = FileForm::toFileForm($map, $boundary);
$this->assertTrue(false !== strpos($fileStream->getContents(), 'json_file'));
}
}

View file

@ -1,3 +0,0 @@
<?php

require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';

View file

@ -1,65 +0,0 @@
<?php
/*
* This document has been generated with
* https://mlocati.github.io/php-cs-fixer-configurator/#version:2.15|configurator
* you can change this configuration by importing this file.
*/

return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setIndent(' ')
->setRules([
'@PSR2' => true,
'@PhpCsFixer' => true,
'@Symfony:risky' => true,
'concat_space' => ['spacing' => 'one'],
'array_syntax' => ['syntax' => 'short'],
'array_indentation' => true,
'combine_consecutive_unsets' => true,
'method_separation' => true,
'single_quote' => true,
'declare_equal_normalize' => true,
'function_typehint_space' => true,
'hash_to_slash_comment' => true,
'include' => true,
'lowercase_cast' => true,
'no_multiline_whitespace_before_semicolons' => true,
'no_leading_import_slash' => true,
'no_multiline_whitespace_around_double_arrow' => true,
'no_spaces_around_offset' => true,
'no_unneeded_control_parentheses' => true,
'no_unused_imports' => true,
'no_whitespace_before_comma_in_array' => true,
'no_whitespace_in_blank_line' => true,
'object_operator_without_whitespace' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => true,
'space_after_semicolon' => true,
'standardize_not_equals' => true,
'ternary_operator_spaces' => true,
'trailing_comma_in_multiline_array' => true,
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'whitespace_after_comma_in_array' => true,
'no_extra_consecutive_blank_lines' => [
'curly_brace_block',
'extra',
'parenthesis_brace_block',
'square_brace_block',
'throw',
'use',
],
'binary_operator_spaces' => [
'align_double_arrow' => true,
'align_equals' => true,
],
'braces' => [
'allow_single_line_closure' => true,
],
])
->setFinder(
PhpCsFixer\Finder::create()
->exclude('vendor')
->exclude('tests')
->in(__DIR__)
);

View file

@ -1,148 +0,0 @@
# CHANGELOG

## 3.1.22 - 2021-05-11

- Deprecate `stream_for` method.

## 3.1.21 - 2021-03-15

- Supported set proxy&timeout on request.

## 3.1.20 - 2020-12-02

- Fix the warning when the Tea::merge method received empty arguments.

## 3.1.19 - 2020-10-09

- Fix the error when the code value is a string.

## 3.1.18 - 2020-09-28

- Require Guzzle Version 7.0

## 3.1.17 - 2020-09-24

- TeaUnableRetryError support get error info.

## 3.1.16 - 2020-08-31

- Fix the Maximum function nesting level error when repeated network requests.

## 3.1.15 - 2020-07-28

- Improved validatePattern method.

## 3.1.14 - 2020-07-03

- Supported set properties of TeaError with `ErrorInfo`.

## 3.1.13 - 2020-06-09

- Reduce dependencies.

## 3.1.12 - 2020-05-13

- Add validate method.
- Supported validate maximun&minimun of property.

## 3.1.11 - 2020-05-07

- Fixed error when class is undefined.

## 3.1.10 - 2020-05-07

- Fixed error when '$item' of array is null

## 3.1.9 - 2020-04-13

- TeaUnableRetryError add $lastException param.

## 3.1.8 - 2020-04-02

- Added some static methods of Model to validate fields of Model.

## 3.1.7 - 2020-03-27

- Improve Tea::isRetryable method.

## 3.1.6 - 2020-03-25

- Fixed bug when body is StreamInterface.

## 3.1.5 - 2020-03-25

- Improve Model.toMap method.
- Improve Tea.merge method.
- Fixed tests.

## 3.1.4 - 2020-03-20

- Added Tea::merge method.
- Change Tea::isRetryable method.

## 3.1.3 - 2020-03-20

- Model: added toModel method.

## 3.1.2 - 2020-03-19

- Model constructor supported array type parameter.

## 3.1.1 - 2020-03-18

- Fixed bug : set method failed.
- Fixed bug : get empty contents form body.

## 3.1.0 - 2020-03-13

- TeaUnableRetryError add 'lastRequest' property.
- Change Tea.send() method return.
- Fixed Tea. allowRetry() method.

## 3.0.0 - 2020-02-14
- Rename package name.

## 2.0.3 - 2020-02-14
- Improved Exception.

## 2.0.2 - 2019-09-11
- Supported `String`.

## 2.0.1 - 2019-08-15
- Supported `IteratorAggregate`.

## 2.0.0 - 2019-08-14
- Design `Request` as a standard `PsrRequest`.

## 1.0.10 - 2019-08-12
- Added `__toString` for `Response`.

## 1.0.9 - 2019-08-01
- Updated `Middleware`.

## 1.0.8 - 2019-07-29
- Supported `TransferStats`.

## 1.0.7 - 2019-07-27
- Improved request.

## 1.0.6 - 2019-07-23
- Trim key for parameter.

## 1.0.5 - 2019-07-23
- Supported default protocol.

## 1.0.4 - 2019-07-22
- Added `toArray()`.

## 1.0.3 - 2019-05-02
- Improved `Request`.

## 1.0.2 - 2019-05-02
- Added getHeader/getHeaders.

## 1.0.1 - 2019-04-02
- Improved design.

## 1.0.0 - 2019-05-02
- Initial release of the AlibabaCloud Tea Version 1.0.0 on Packagist See <https://github.com/aliyun/tea-php> for more information.

View file

@ -1,13 +0,0 @@
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1,16 +0,0 @@

## Installation
```
composer require alibabacloud/tea --optimize-autoloader
```
> Some users may not be able to install due to network problems, you can try to switch the Composer mirror.


## Changelog
Detailed changes for each release are documented in the [release notes](CHANGELOG.md).


## License
[Apache-2.0](LICENSE.md)

Copyright (c) 2009-present, Alibaba Cloud All rights reserved.

View file

@ -1,80 +0,0 @@
{
"name": "alibabacloud/tea",
"homepage": "https://www.alibabacloud.com/",
"description": "Client of Tea for PHP",
"keywords": [
"tea",
"client",
"alibabacloud",
"cloud"
],
"type": "library",
"license": "Apache-2.0",
"support": {
"source": "https://github.com/aliyun/tea-php",
"issues": "https://github.com/aliyun/tea-php/issues"
},
"authors": [
{
"name": "Alibaba Cloud SDK",
"email": "sdk-team@alibabacloud.com",
"homepage": "http://www.alibabacloud.com"
}
],
"require": {
"php": ">=5.5",
"ext-curl": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-simplexml": "*",
"ext-xmlwriter": "*",
"guzzlehttp/guzzle": "^6.3|^7.0",
"adbario/php-dot-notation": "^2.4"
},
"require-dev": {
"symfony/dotenv": "^3.4",
"phpunit/phpunit": "*",
"symfony/var-dumper": "^3.4"
},
"suggest": {
"ext-sockets": "To use client-side monitoring"
},
"autoload": {
"psr-4": {
"AlibabaCloud\\Tea\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"AlibabaCloud\\Tea\\Tests\\": "tests"
}
},
"config": {
"sort-packages": true,
"preferred-install": "dist",
"optimize-autoloader": true
},
"prefer-stable": true,
"minimum-stability": "dev",
"scripts": {
"cs": "phpcs --standard=PSR2 -n ./",
"cbf": "phpcbf --standard=PSR2 -n ./",
"fixer": "php-cs-fixer fix ./",
"test": [
"@clearCache",
"phpunit --colors=always"
],
"unit": [
"@clearCache",
"phpunit --testsuite=Unit --colors=always"
],
"feature": [
"@clearCache",
"phpunit --testsuite=Feature --colors=always"
],
"clearCache": "rm -rf cache/*",
"coverage": "open cache/coverage/index.html"
}
}

View file

@ -1,53 +0,0 @@
<?php

namespace AlibabaCloud\Tea\Exception;

use RuntimeException;

/**
* Class TeaError.
*/
class TeaError extends RuntimeException
{
public $message = '';
public $code = 0;
public $data;
public $name = '';
public $statusCode;
public $description;
public $accessDeniedDetail;
private $errorInfo;

/**
* TeaError constructor.
*
* @param array $errorInfo
* @param string $message
* @param int $code
* @param null|\Throwable $previous
*/
public function __construct($errorInfo = [], $message = '', $code = 0, $previous = null)
{
parent::__construct((string) $message, (int) $code, $previous);
$this->errorInfo = $errorInfo;
if (!empty($errorInfo)) {
$properties = ['name', 'message', 'code', 'data', 'description', 'accessDeniedDetail'];
foreach ($properties as $property) {
if (isset($errorInfo[$property])) {
$this->{$property} = $errorInfo[$property];
if ($property === 'data' && isset($errorInfo['data']['statusCode'])) {
$this->statusCode = $errorInfo['data']['statusCode'];
}
}
}
}
}

/**
* @return array
*/
public function getErrorInfo()
{
return $this->errorInfo;
}
}

View file

@ -1,21 +0,0 @@
<?php

namespace AlibabaCloud\Tea\Exception;

/**
* Class TeaRetryError.
*/
class TeaRetryError extends TeaError
{
/**
* TeaRetryError constructor.
*
* @param string $message
* @param int $code
* @param null|\Throwable $previous
*/
public function __construct($message = '', $code = 0, $previous = null)
{
parent::__construct([], $message, $code, $previous);
}
}

View file

@ -1,41 +0,0 @@
<?php

namespace AlibabaCloud\Tea\Exception;

use AlibabaCloud\Tea\Request;

/**
* Class TeaUnableRetryError.
*/
class TeaUnableRetryError extends TeaError
{
private $lastRequest;
private $lastException;

/**
* TeaUnableRetryError constructor.
*
* @param Request $lastRequest
* @param null|\Exception $lastException
*/
public function __construct($lastRequest, $lastException = null)
{
$error_info = [];
if (null !== $lastException && $lastException instanceof TeaError) {
$error_info = $lastException->getErrorInfo();
}
parent::__construct($error_info, $lastException->getMessage(), $lastException->getCode(), $lastException);
$this->lastRequest = $lastRequest;
$this->lastException = $lastException;
}

public function getLastRequest()
{
return $this->lastRequest;
}

public function getLastException()
{
return $this->lastException;
}
}

View file

@ -1,112 +0,0 @@
<?php

namespace AlibabaCloud\Tea;

class Helper
{
/**
* @param string $content
* @param string $prefix
* @param string $end
* @param string[] $filter
*
* @return string|string[]
*/
public static function findFromString($content, $prefix, $end, $filter = ['"', ' '])
{
$len = mb_strlen($prefix);
$pos = mb_strpos($content, $prefix);
if (false === $pos) {
return '';
}
$pos_end = mb_strpos($content, $end, $pos);
$str = mb_substr($content, $pos + $len, $pos_end - $pos - $len);

return str_replace($filter, '', $str);
}

/**
* @param string $str
*
* @return bool
*/
public static function isJson($str)
{
json_decode($str);

return \JSON_ERROR_NONE == json_last_error();
}

/**
* @param mixed $value
*
* @return bool
*/
public static function isBytes($value)
{
if (!\is_array($value)) {
return false;
}
$i = 0;
foreach ($value as $k => $ord) {
if ($k !== $i) {
return false;
}
if (!\is_int($ord)) {
return false;
}
if ($ord < 0 || $ord > 255) {
return false;
}
++$i;
}

return true;
}

/**
* Convert a bytes to string(utf8).
*
* @param array $bytes
*
* @return string the return string
*/
public static function toString($bytes)
{
$str = '';
foreach ($bytes as $ch) {
$str .= \chr($ch);
}

return $str;
}

/**
* @return array
*/
public static function merge(array $arrays)
{
$result = [];
foreach ($arrays as $array) {
foreach ($array as $key => $value) {
if (\is_int($key)) {
$result[] = $value;

continue;
}

if (isset($result[$key]) && \is_array($result[$key])) {
$result[$key] = self::merge(
[$result[$key], $value]
);

continue;
}

$result[$key] = $value;
}
}

return $result;
}
}

View file

@ -1,114 +0,0 @@
<?php

namespace AlibabaCloud\Tea;

class Model
{
protected $_name = [];
protected $_required = [];

public function __construct($config = [])
{
if (!empty($config)) {
foreach ($config as $k => $v) {
$this->{$k} = $v;
}
}
}

public function getName($name = null)
{
if (null === $name) {
return $this->_name;
}

return isset($this->_name[$name]) ? $this->_name[$name] : $name;
}

public function toMap()
{
$map = get_object_vars($this);
foreach ($map as $k => $m) {
if (0 === strpos($k, '_')) {
unset($map[$k]);
}
}
$res = [];
foreach ($map as $k => $v) {
$name = isset($this->_name[$k]) ? $this->_name[$k] : $k;
$res[$name] = $v;
}

return $res;
}

public function validate()
{
$vars = get_object_vars($this);
foreach ($vars as $k => $v) {
if (isset($this->_required[$k]) && $this->_required[$k] && empty($v)) {
throw new \InvalidArgumentException("{$k} is required.");
}
}
}

public static function validateRequired($fieldName, $field, $val = null)
{
if (true === $val && null === $field) {
throw new \InvalidArgumentException($fieldName . ' is required');
}
}

public static function validateMaxLength($fieldName, $field, $val = null)
{
if (null !== $field && \strlen($field) > (int) $val) {
throw new \InvalidArgumentException($fieldName . ' is exceed max-length: ' . $val);
}
}

public static function validateMinLength($fieldName, $field, $val = null)
{
if (null !== $field && \strlen($field) < (int) $val) {
throw new \InvalidArgumentException($fieldName . ' is less than min-length: ' . $val);
}
}

public static function validatePattern($fieldName, $field, $regex = '')
{
if (null !== $field && '' !== $field && !preg_match("/^{$regex}$/", $field)) {
throw new \InvalidArgumentException($fieldName . ' is not match ' . $regex);
}
}

public static function validateMaximum($fieldName, $field, $val)
{
if (null !== $field && $field > $val) {
throw new \InvalidArgumentException($fieldName . ' cannot be greater than ' . $val);
}
}

public static function validateMinimum($fieldName, $field, $val)
{
if (null !== $field && $field < $val) {
throw new \InvalidArgumentException($fieldName . ' cannot be less than ' . $val);
}
}

/**
* @param array $map
* @param Model $model
*
* @return mixed
*/
public static function toModel($map, $model)
{
$names = $model->getName();
$names = array_flip($names);
foreach ($map as $key => $value) {
$name = isset($names[$key]) ? $names[$key] : $key;
$model->{$name} = $value;
}

return $model;
}
}

View file

@ -1,50 +0,0 @@
<?php

namespace AlibabaCloud\Tea;

use ArrayIterator;
use IteratorAggregate;
use ReflectionObject;
use Traversable;

/**
* Class Parameter.
*/
abstract class Parameter implements IteratorAggregate
{
/**
* @return ArrayIterator|Traversable
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new ArrayIterator($this->toArray());
}

/**
* @return array
*/
public function getRealParameters()
{
$array = [];
$obj = new ReflectionObject($this);
$properties = $obj->getProperties();

foreach ($properties as $property) {
$docComment = $property->getDocComment();
$key = trim(Helper::findFromString($docComment, '@real', "\n"));
$value = $property->getValue($this);
$array[$key] = $value;
}

return $array;
}

/**
* @return array
*/
public function toArray()
{
return $this->getRealParameters();
}
}

View file

@ -1,123 +0,0 @@
<?php

namespace AlibabaCloud\Tea;

use GuzzleHttp\Psr7\Request as PsrRequest;
use InvalidArgumentException;
use Psr\Http\Message\StreamInterface;

/**
* Class Request.
*/
class Request extends PsrRequest
{
/**
* @var string
*/
public $protocol = 'https';

/**
* @var string
*/
public $pathname = '/';

/**
* @var array
*/
public $headers = [];

/**
* @var array
*/
public $query = [];

/**
* @var string
*/
public $body;

/**
* @var int
*/
public $port;

public $method;

public function __construct($method = 'GET', $uri = '', array $headers = [], $body = null, $version = '1.1')
{
parent::__construct($method, $uri, $headers, $body, $version);
$this->method = $method;
}

/**
* These fields are compatible if you define other fields.
* Mainly for compatibility situations where the code generator cannot generate set properties.
*
* @return PsrRequest
*/
public function getPsrRequest()
{
$this->assertQuery($this->query);

$request = clone $this;

$uri = $request->getUri();
if ($this->query) {
$uri = $uri->withQuery(http_build_query($this->query));
}

if ($this->port) {
$uri = $uri->withPort($this->port);
}

if ($this->protocol) {
$uri = $uri->withScheme($this->protocol);
}

if ($this->pathname) {
$uri = $uri->withPath($this->pathname);
}

if (isset($this->headers['host'])) {
$uri = $uri->withHost($this->headers['host']);
}

$request = $request->withUri($uri);
$request = $request->withMethod($this->method);

if ('' !== $this->body && null !== $this->body) {
if ($this->body instanceof StreamInterface) {
$request = $request->withBody($this->body);
} else {
$body = $this->body;
if (Helper::isBytes($this->body)) {
$body = Helper::toString($this->body);
}
if (\function_exists('\GuzzleHttp\Psr7\stream_for')) {
// @deprecated stream_for will be removed in guzzlehttp/psr7:2.0
$request = $request->withBody(\GuzzleHttp\Psr7\stream_for($body));
} else {
$request = $request->withBody(\GuzzleHttp\Psr7\Utils::streamFor($body));
}
}
}

if ($this->headers) {
foreach ($this->headers as $key => $value) {
$request = $request->withHeader($key, $value);
}
}

return $request;
}

/**
* @param array $query
*/
private function assertQuery($query)
{
if (!\is_array($query) && $query !== null) {
throw new InvalidArgumentException('Query must be array.');
}
}
}

View file

@ -1,372 +0,0 @@
<?php

namespace AlibabaCloud\Tea;

use Adbar\Dot;
use ArrayAccess;
use Countable;
use GuzzleHttp\Psr7\Response as PsrResponse;
use GuzzleHttp\TransferStats;
use IteratorAggregate;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;

/**
* Class Response.
*/
class Response extends PsrResponse implements ArrayAccess, IteratorAggregate, Countable
{
public $headers = [];
public $statusCode;
public $statusMessage = '';

/**
* @var TransferStats
*/
public static $info;

/**
* @var StreamInterface
*/
public $body;
/**
* Instance of the Dot.
*
* @var Dot
*/
protected $dot;

/**
* Response constructor.
*/
public function __construct(ResponseInterface $response)
{
parent::__construct(
$response->getStatusCode(),
$response->getHeaders(),
$response->getBody(),
$response->getProtocolVersion(),
$response->getReasonPhrase()
);
$this->headers = $response->getHeaders();
$this->body = $response->getBody();
$this->statusCode = $response->getStatusCode();
if ($this->body->isSeekable()) {
$this->body->seek(0);
}

if (Helper::isJson((string) $this->getBody())) {
$this->dot = new Dot($this->toArray());
} else {
$this->dot = new Dot();
}
}

/**
* @return string
*/
public function __toString()
{
return (string) $this->getBody();
}

/**
* @param string $name
*
* @return null|mixed
*/
public function __get($name)
{
$data = $this->dot->all();
if (!isset($data[$name])) {
return null;
}

return json_decode(json_encode($data))->{$name};
}

/**
* @param string $name
* @param mixed $value
*/
public function __set($name, $value)
{
$this->dot->set($name, $value);
}

/**
* @param string $name
*
* @return bool
*/
public function __isset($name)
{
return $this->dot->has($name);
}

/**
* @param $offset
*/
public function __unset($offset)
{
$this->dot->delete($offset);
}

/**
* @return array
*/
public function toArray()
{
return \GuzzleHttp\json_decode((string) $this->getBody(), true);
}

/**
* @param array|int|string $keys
* @param mixed $value
*/
public function add($keys, $value = null)
{
return $this->dot->add($keys, $value);
}

/**
* @return array
*/
public function all()
{
return $this->dot->all();
}

/**
* @param null|array|int|string $keys
*/
public function clear($keys = null)
{
return $this->dot->clear($keys);
}

/**
* @param array|int|string $keys
*/
public function delete($keys)
{
return $this->dot->delete($keys);
}

/**
* @param string $delimiter
* @param null|array $items
* @param string $prepend
*
* @return array
*/
public function flatten($delimiter = '.', $items = null, $prepend = '')
{
return $this->dot->flatten($delimiter, $items, $prepend);
}

/**
* @param null|int|string $key
* @param mixed $default
*
* @return mixed
*/
public function get($key = null, $default = null)
{
return $this->dot->get($key, $default);
}

/**
* @param array|int|string $keys
*
* @return bool
*/
public function has($keys)
{
return $this->dot->has($keys);
}

/**
* @param null|array|int|string $keys
*
* @return bool
*/
public function isEmpty($keys = null)
{
return $this->dot->isEmpty($keys);
}

/**
* @param array|self|string $key
* @param array|self $value
*/
public function merge($key, $value = [])
{
return $this->dot->merge($key, $value);
}

/**
* @param array|self|string $key
* @param array|self $value
*/
public function mergeRecursive($key, $value = [])
{
return $this->dot->mergeRecursive($key, $value);
}

/**
* @param array|self|string $key
* @param array|self $value
*/
public function mergeRecursiveDistinct($key, $value = [])
{
return $this->dot->mergeRecursiveDistinct($key, $value);
}

/**
* @param null|int|string $key
* @param mixed $default
*
* @return mixed
*/
public function pull($key = null, $default = null)
{
return $this->dot->pull($key, $default);
}

/**
* @param null|int|string $key
* @param mixed $value
*
* @return mixed
*/
public function push($key = null, $value = null)
{
return $this->dot->push($key, $value);
}

/**
* Replace all values or values within the given key
* with an array or Dot object.
*
* @param array|self|string $key
* @param array|self $value
*/
public function replace($key, $value = [])
{
return $this->dot->replace($key, $value);
}

/**
* Set a given key / value pair or pairs.
*
* @param array|int|string $keys
* @param mixed $value
*/
public function set($keys, $value = null)
{
return $this->dot->set($keys, $value);
}

/**
* Replace all items with a given array.
*
* @param mixed $items
*/
public function setArray($items)
{
return $this->dot->setArray($items);
}

/**
* Replace all items with a given array as a reference.
*/
public function setReference(array &$items)
{
return $this->dot->setReference($items);
}

/**
* Return the value of a given key or all the values as JSON.
*
* @param mixed $key
* @param int $options
*
* @return string
*/
public function toJson($key = null, $options = 0)
{
return $this->dot->toJson($key, $options);
}

/**
* Retrieve an external iterator.
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return $this->dot->getIterator();
}

/**
* Whether a offset exists.
*
* @param $offset
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return $this->dot->offsetExists($offset);
}

/**
* Offset to retrieve.
*
* @param $offset
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->dot->offsetGet($offset);
}

/**
* Offset to set.
*
* @param $offset
* @param $value
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
$this->dot->offsetSet($offset, $value);
}

/**
* Offset to unset.
*
* @param $offset
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
$this->dot->offsetUnset($offset);
}

/**
* Count elements of an object.
*
* @param null $key
*
* @return int
*/
#[\ReturnTypeWillChange]
public function count($key = null)
{
return $this->dot->count($key);
}
}

View file

@ -1,287 +0,0 @@
<?php

namespace AlibabaCloud\Tea;

use Adbar\Dot;
use AlibabaCloud\Tea\Exception\TeaError;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\TransferStats;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;

/**
* Class Tea.
*/
class Tea
{
/**
* @var array
*/
private static $config = [];

public static function config(array $config)
{
self::$config = $config;
}

/**
* @throws GuzzleException
*
* @return Response
*/
public static function send(Request $request, array $config = [])
{
if (method_exists($request, 'getPsrRequest')) {
$request = $request->getPsrRequest();
}

$config = self::resolveConfig($config);

$res = self::client()->send(
$request,
$config
);

return new Response($res);
}

/**
* @return PromiseInterface
*/
public static function sendAsync(RequestInterface $request, array $config = [])
{
if (method_exists($request, 'getPsrRequest')) {
$request = $request->getPsrRequest();
}

$config = self::resolveConfig($config);

return self::client()->sendAsync(
$request,
$config
);
}

/**
* @return Client
*/
public static function client(array $config = [])
{
if (isset(self::$config['handler'])) {
$stack = self::$config['handler'];
} else {
$stack = HandlerStack::create();
$stack->push(Middleware::mapResponse(static function (ResponseInterface $response) {
return new Response($response);
}));
}

self::$config['handler'] = $stack;

if (!isset(self::$config['on_stats'])) {
self::$config['on_stats'] = function (TransferStats $stats) {
Response::$info = $stats->getHandlerStats();
};
}

$new_config = Helper::merge([self::$config, $config]);

return new Client($new_config);
}

/**
* @param string $method
* @param string|UriInterface $uri
* @param array $options
*
* @throws GuzzleException
*
* @return ResponseInterface
*/
public static function request($method, $uri, $options = [])
{
return self::client()->request($method, $uri, $options);
}

/**
* @param string $method
* @param string $uri
* @param array $options
*
* @throws GuzzleException
*
* @return string
*/
public static function string($method, $uri, $options = [])
{
return (string) self::client()->request($method, $uri, $options)
->getBody();
}

/**
* @param string $method
* @param string|UriInterface $uri
* @param array $options
*
* @return PromiseInterface
*/
public static function requestAsync($method, $uri, $options = [])
{
return self::client()->requestAsync($method, $uri, $options);
}

/**
* @param string|UriInterface $uri
* @param array $options
*
* @throws GuzzleException
*
* @return null|mixed
*/
public static function getHeaders($uri, $options = [])
{
return self::request('HEAD', $uri, $options)->getHeaders();
}

/**
* @param string|UriInterface $uri
* @param string $key
* @param null|mixed $default
*
* @throws GuzzleException
*
* @return null|mixed
*/
public static function getHeader($uri, $key, $default = null)
{
$headers = self::getHeaders($uri);

return isset($headers[$key][0]) ? $headers[$key][0] : $default;
}

/**
* @param int $retryTimes
* @param float $now
*
* @return bool
*/
public static function allowRetry(array $runtime, $retryTimes, $now)
{
unset($now);
if (!isset($retryTimes) || null === $retryTimes || !\is_numeric($retryTimes)) {
return false;
}
if ($retryTimes > 0 && (empty($runtime) || !isset($runtime['retryable']) || !$runtime['retryable'] || !isset($runtime['maxAttempts']))) {
return false;
}
$maxAttempts = $runtime['maxAttempts'];
$retry = empty($maxAttempts) ? 0 : (int) $maxAttempts;

return $retry >= $retryTimes;
}

/**
* @param int $retryTimes
*
* @return int
*/
public static function getBackoffTime(array $runtime, $retryTimes)
{
$backOffTime = 0;
$policy = isset($runtime['policy']) ? $runtime['policy'] : '';

if (empty($policy) || 'no' == $policy) {
return $backOffTime;
}

$period = isset($runtime['period']) ? $runtime['period'] : '';
if (null !== $period && '' !== $period) {
$backOffTime = (int) $period;
if ($backOffTime <= 0) {
return $retryTimes;
}
}

return $backOffTime;
}

public static function sleep($time)
{
sleep($time);
}

public static function isRetryable($retry, $retryTimes = 0)
{
if ($retry instanceof TeaError) {
return true;
}
if (\is_array($retry)) {
$max = isset($retry['maxAttempts']) ? (int) ($retry['maxAttempts']) : 3;

return $retryTimes <= $max;
}

return false;
}

/**
* @param mixed|Model[] ...$item
*
* @return mixed
*/
public static function merge(...$item)
{
$tmp = [];
$n = 0;
foreach ($item as $i) {
if (\is_object($i)) {
if ($i instanceof Model) {
$i = $i->toMap();
} else {
$i = json_decode(json_encode($i), true);
}
}
if (null === $i) {
continue;
}
if (\is_array($i)) {
$tmp[$n++] = $i;
}
}

if (\count($tmp)) {
return \call_user_func_array('array_merge', $tmp);
}

return [];
}

private static function resolveConfig(array $config = [])
{
$options = new Dot(['http_errors' => false]);
if (isset($config['httpProxy']) && !empty($config['httpProxy'])) {
$options->set('proxy.http', $config['httpProxy']);
}
if (isset($config['httpsProxy']) && !empty($config['httpsProxy'])) {
$options->set('proxy.https', $config['httpsProxy']);
}
if (isset($config['noProxy']) && !empty($config['noProxy'])) {
$options->set('proxy.no', $config['noProxy']);
}
if (isset($config['ignoreSSL']) && !empty($config['ignoreSSL'])) {
$options->set('verify',!((bool)$config['ignoreSSL']));
}
// readTimeout&connectTimeout unit is millisecond
$read_timeout = isset($config['readTimeout']) && !empty($config['readTimeout']) ? (int) $config['readTimeout'] : 0;
$con_timeout = isset($config['connectTimeout']) && !empty($config['connectTimeout']) ? (int) $config['connectTimeout'] : 0;
// timeout unit is second
$options->set('timeout', ($read_timeout + $con_timeout) / 1000);

return $options->all();
}
}

View file

@ -1 +0,0 @@
*.* linguist-language=java

View file

@ -1,16 +0,0 @@
.DS_Store
node_modules
logs
.libraries.json
libraries

.idea
*.iml
target
dependency-reduced-pom.xml

bin
obj
.vs

publish/alipay-easysdk

View file

@ -1,822 +0,0 @@
# 基础能力 Base
## 用户授权 OAuth
### 获取授权访问令牌
* API声明

getToken(code: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| code | string | 是 | 授权码,用户对应用授权后得到 |

* 出参说明

可前往[alipay.system.oauth.token](https://docs.open.alipay.com/api_9/alipay.system.oauth.token)查看更加详细的参数说明。

### 刷新授权访问令牌
* API声明

refreshToken(refreshToken: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| refreshToken | string | 是 | 刷新令牌上次换取访问令牌时得到见出参的refresh_token字段 |

* 出参说明

可前往[alipay.system.oauth.token](https://docs.open.alipay.com/api_9/alipay.system.oauth.token)查看更加详细的参数说明。

---

## 小程序二维码 Qrcode
### 创建小程序二维码
* API声明

create(urlParam: string, queryParam: string, describe: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| urlParam | string | 是 | 小程序中能访问到的页面路径例如page/component/component-pages/view/view |
| queryParam | string | 是 | 小程序的启动参数打开小程序的query ,在小程序 onLaunch的方法中获取 |
| describe | string | 是 | 二维码描述 |

* 出参说明

可前往[alipay.open.app.qrcode.create](https://docs.open.alipay.com/api_5/alipay.open.app.qrcode.create)查看更加详细的参数说明。

---

## 图片 Image
### 上传图片
* API声明

upload(imageName: string, imageFilePath: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| imageName | string | 是 | 图片名称 |
| imageFilePath | string | 是 | 待上传的本地图片文件路径 |

* 出参说明

可前往[alipay.offline.material.image.upload](https://docs.open.alipay.com/api_3/alipay.offline.material.image.upload)查看更加详细的参数说明。

---

## 视频 Video
### 上传视频
* API声明

upload(videoName: string, videoFilePath: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| videoName | string | 是 | 视频名称 |
| videoFilePath | string | 是 | 待上传的本地视频文件路径 |

* 出参说明

可前往[alipay.offline.material.image.upload](https://docs.open.alipay.com/api_3/alipay.offline.material.image.upload)查看更加详细的参数说明。

---

# 营销能力 Marketing
## 生活号 OpenLife
### 创建图文消息内容
* API声明

createImageTextContent(title: string, cover: string, content: string, contentComment: string, ctype: string, benefit: string, extTags: string, loginIds: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| title | string | 是 | 标题 |
| cover | string | 是 | 封面图URL, 尺寸为996*450最大不超过3M支持.jpg、.png格式请先调用上传图片接口获得图片URL |
| content | string | 是 | 消息正文(支持富文本) |
| contentComment | string | 否 | 是否允许评论T允许F不允许默认不允许 |
| ctype | string | 否 | 图文类型填activity表示活动图文不填默认普通图文 |
| benefit | string | 否 | 活动利益点图文类型ctype为activity类型时才需要传最多10个字符 |
| extTags | string | 否 | 关键词列表英文逗号分隔最多不超过5个 |
| loginIds | string | 否 | 可预览支付宝账号列表,需要预览时才填写, 英文逗号分隔最多不超过10个 |

* 出参说明

可前往[alipay.open.public.message.content.create](https://docs.open.alipay.com/api_6/alipay.open.public.message.content.create)查看更加详细的参数说明。

### 更新图文消息内容
* API声明

modifyImageTextContent(contentId: string, title: string, cover: string, content: string, couldComment: string, ctype: string, benefit: string, extTags: string, loginIds: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| contentId | string | 是 | 内容ID通过创建图文内容消息接口返回 |
| title | string | 是 | 标题 |
| cover | string | 是 | 封面图URL, 尺寸为996*450最大不超过3M支持.jpg、.png格式请先调用上传图片接口获得图片URL |
| content | string | 是 | 消息正文(支持富文本) |
| contentComment | string | 否 | 是否允许评论T允许F不允许默认不允许 |
| ctype | string | 否 | 图文类型填activity表示活动图文不填默认普通图文 |
| benefit | string | 否 | 活动利益点图文类型ctype为activity类型时才需要传最多10个字符 |
| extTags | string | 否 | 关键词列表英文逗号分隔最多不超过5个 |
| loginIds | string | 否 | 可预览支付宝账号列表,需要预览时才填写, 英文逗号分隔最多不超过10个 |

* 出参说明

可前往[alipay.open.public.message.content.modify](https://docs.open.alipay.com/api_6/alipay.open.public.message.content.modify)查看更加详细的参数说明。

### 群发本文消息
* API声明

sendText(text: string)
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| text | string | 是 | 文本消息内容 |

* 出参说明

可前往[alipay.open.public.message.total.send](https://docs.open.alipay.com/api_6/alipay.open.public.message.total.send)查看更加详细的参数说明。

### 群发图文消息
* API声明

sendImageText(articles: [ Article ])
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| articles | Article数组 | 是 | 图文消息内容 |

Article对象说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| title | string | 否 | 图文消息标题 |
| desc | string | 是 | 图文消息描述 |
| imageUrl | string | 特殊可选 | 图片链接对于多条图文消息的第一条消息该字段不能为空请先调用上传图片接口获得图片URL |
| url | string | 是 | 点击图文消息跳转的链接 |
| actionName | string | 否 | 链接文字 |

* 出参说明

可前往[alipay.open.public.message.total.send](https://docs.open.alipay.com/api_6/alipay.open.public.message.total.send)查看更加详细的参数说明。

### 单发模板消息
* API声明

sendSingleMessage(toUserId: string, template: Template)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| toUserId | string | 是 | 消息接收用户的UserId |
| template | Template | 是 | 消息接收用户的UserId |

Template对象说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| templateId | string | 是 | 消息模板ID |
| context | Context | 是 | 消息模板上下文,即模板中定义的参数及参数值 |

Context对象说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| headColor | string | 是 | 顶部色条的色值,比如#85be53 |
| url | string | 是 | 点击消息后承接页的地址 |
| actionName | string | 是 | 底部链接描述文字“查看详情”最多能传8个汉字或16个英文字符 |
| keyword1 | Keyword | 否 | 模板中占位符的值及文字颜色 |
| keyword2 | Keyword | 否 | 模板中占位符的值及文字颜色 |
| first | Keyword | 否 | 模板中占位符的值及文字颜色 |
| remark | Keyword | 否 | 模板中占位符的值及文字颜色 |

Keyword对象说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| color | string | 是 | 当前文字颜色,比如#85be53 |
| value | string | 是 | 模板中占位符的值 |

* 出参说明

可前往[alipay.open.public.message.single.send](https://docs.open.alipay.com/api_6/alipay.open.public.message.single.send)查看更加详细的参数说明。

### 生活号消息撤回
* API声明

recallMessage(messageId: string)
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| messageId | string | 是 | 消息ID |

* 出参说明

可前往[alipay.open.public.life.msg.recall](https://docs.open.alipay.com/api_6/alipay.open.public.life.msg.recall)查看更加详细的参数说明。

### 模板消息行业设置
* API声明

setIndustry(primaryIndustryCode: string, primaryIndustryName: string, secondaryIndustryCode: string, secondaryIndustryName: string)
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| primaryIndustryCode | string | 是 | 服务窗消息模板所属主行业一级编码,查看[行业信息](https://alipay.open.taobao.com/doc2/detail?treeId=197&docType=1&articleId=105043) |
| primaryIndustryName | string | 是 | 服务窗消息模板所属主行业一级名称 |
| secondaryIndustryCode | string | 是 | 服务窗消息模板所属主行业二级编码 |
| secondaryIndustryName | string | 是 | 服务窗消息模板所属主行业二级名称 |

* 出参说明

可前往[alipay.open.public.template.message.industry.modify](https://docs.open.alipay.com/api_6/alipay.open.public.template.message.industry.modify)查看更加详细的参数说明。

### 生活号查询行业设置
* API声明

getIndustry()
* 入参说明


* 出参说明

可前往[alipay.open.public.setting.category.query](https://docs.open.alipay.com/api_6/alipay.open.public.setting.category.query)查看更加详细的参数说明。

---


## 支付宝卡包 Pass
### 卡券模板创建
* API声明

createTemplate(uniqueId: string, tplContent: string)
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| uniqueId | string | 是 | 商户用于控制模版的唯一性(可以使用时间戳保证唯一性) |
| tplContent | string | 是 | 模板内容信息遵循JSON规范详情参见tpl_content[参数说明](https://doc.open.alipay.com/doc2/detail.htm?treeId=193&articleId=105249&docType=1#tpl_content) |

* 出参说明

可前往[alipay.pass.template.add](https://docs.open.alipay.com/api_24/alipay.pass.template.add)查看更加详细的参数说明。

### 卡券模板更新
* API声明

updateTemplate(uniqueId: string, tplContent: string)
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| uniqueId | string | 是 | 商户用于控制模版的唯一性(可以使用时间戳保证唯一性) |
| tplContent | string | 是 | 模板内容信息遵循JSON规范详情参见tpl_content[参数说明](https://doc.open.alipay.com/doc2/detail.htm?treeId=193&articleId=105249&docType=1#tpl_content) |

* 出参说明

可前往[alipay.pass.template.update](https://docs.open.alipay.com/api_24/alipay.pass.template.update)查看更加详细的参数说明。

### 卡券实例发放
* API声明

addInstance(tplId: string, tplParams: string, recognitionType: string, recognitionInfo: string)
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| tplId | string | 是 | 支付宝pass模版ID即调用模板创建接口时返回的tpl_id |
| tplParams | string | 是 | 模版动态参数信息,对应模板中$变量名$的动态参数见模板创建接口返回值中的tpl_params字段。示例 |
| recognitionType | string | 是 | Alipass添加对象识别类型填写“1”表示订单信息 |
| recognitionInfo | string | 是 | 支付宝用户识别信息,参见[UID发券组件对接文档](https://docs.open.alipay.com/199/sy3hs4 ) |

* 出参说明

可前往[alipay.pass.instance.add](https://docs.open.alipay.com/api_24/alipay.pass.instance.add)查看更加详细的参数说明。

### 卡券实例更新
* API声明

updateInstance(serialNumber: string, channelId: string, tplParams: string, status: string, verifyCode: string, verifyType: string)
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| serialNumber | string | 是 | 商户指定卡券唯一值卡券JSON模板中fileInfo->serialNumber字段对应的值 |
| channelId | string | 是 | 代理商代替商户发放卡券后再代替商户更新卡券时此值为商户的PID/AppID |
| tplParams | string | 否 | Alipass添加对象识别类型填写“1”表示订单信息 |
| status | string | 否 | 券状态支持更新为USED、CLOSED两种状态 |
| verifyCode | string | 否 | 核销码串值当状态变更为USED时建议传该值正常为模板中核销区域Operation对应的message值 |
| verifyType | string | 否 | 核销方式该值正常为模板中核销区域Operation对应的format值verifyCode和verifyType需同时传入 |

* 出参说明

可前往[alipay.pass.instance.update](https://docs.open.alipay.com/api_24/alipay.pass.instance.update)查看更加详细的参数说明。

---


## 小程序模板消息 TemplateMessage
### 发送模板消息
* API声明

send(toUserId: string, formId: string, userTemplateId: string, page: string, data: string)
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| toUserId | string | 是 | 发送消息的支付宝账号 |
| formId | string | 是 | 用户发生的交易行为的交易号,或者用户在小程序产生表单提交的表单号,用于信息发送的校验 |
| userTemplateId | string | 是 | 用户申请的模板id号固定的模板id会发送固定的消息 |
| page | string | 是 | 小程序的跳转页面用于消息中心用户点击之后详细跳转的小程序页面例如page/component/index |
| data | string | 是 | 开发者需要发送模板消息中的自定义部分来替换模板的占位符,例如:{"keyword1": {"value" : "12:00"},"keyword2": {"value" : "20180808"},"keyword3": {"value" : "支付宝"}} |

* 出参说明

可前往[alipay.open.app.mini.templatemessage.send](https://docs.open.alipay.com/api_5/alipay.open.app.mini.templatemessage.send)查看更加详细的参数说明。

---


# 会员能力 Member
## 支付宝身份认证 Identification
### 身份认证初始化
* API声明

init(outerOrderNo: string, bizCode: string, identityParam: IdentityParam, merchantConfig: MerchantConfig)
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| outerOrderNo | string | 是 | 商户请求的唯一标识商户要保证其唯一性值为32位长度的字母数字组合建议前面几位字符是商户自定义的简称中间可以使用一段时间后段可以使用一个随机或递增序列 |
| bizCode | string | 是 | 认证场景码入参支持的认证场景码和商户签约的认证场景相关可选值有如下FACE多因子人脸认证CERT_PHOTO多因子证照认证CERT_PHOTO_FACE多因子证照和人脸认证SMART_FACE多因子快捷认证 |
| identityParam | IdentityParam | 是 | 需要验证的身份信息参数 |
| merchantConfig | MerchantConfig | 是 | 商户个性化配置 |

IdentityParam对象说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| identityType | string | 是 | 身份信息参数类型必须传入CERT_INFO |
| certType | string | 是 | 证件类型当前支持身份证必须传入IDENTITY_CARD |
| certName | string | 是 | 真实姓名 |
| certNo | string | 是 | 证件号码 |

MerchantConfig对象说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| returnUrl | string | 是 | 需要回跳的目标URL地址一般指定为商户业务页面 |

* 出参说明

可前往[alipay.user.certify.open.initialize](https://docs.open.alipay.com/api_2/alipay.user.certify.open.initialize)查看更加详细的参数说明。

### 生成认证链接
* API声明

certify(certifyId: string)
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| certifyId | string | 是 | 本次申请操作的唯一标识,由身份认证初始化接口调用后生成,后续的操作都需要用到 |

* 出参说明

可前往[alipay.user.certify.open.certify](https://docs.open.alipay.com/api_2/alipay.user.certify.open.certify)查看更加详细的参数说明。

### 身份认证记录查询
* API声明

query(certifyId: string)
* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| certifyId | string | 是 | 身份认证操作的唯一标识,由身份认证初始化接口调用后生成 |

* 出参说明

可前往[alipay.user.certify.open.query](https://docs.open.alipay.com/api_2/alipay.user.certify.open.query)查看更加详细的参数说明。

---


# 支付能力 Payment
## 通用接口 Common
### 创建交易
* API声明

create(subject: string, outTradeNo: string, totalAmount: string, buyerId: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| subject | string | 是 | 订单标题 |
| outTradeNo | string | 是 | 商户订单号64个字符以内可包含字母、数字、下划线需保证在商户端不重复 |
| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] |
| buyerId | string | 是 | 买家的支付宝唯一用户号2088开头的16位纯数字 |

* 出参说明

可前往[alipay.trade.create](https://docs.open.alipay.com/api_1/alipay.trade.create)查看更加详细的参数说明。

### 查询交易
* API声明

query(outTradeNo: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| outTradeNo | string | 是 | 交易创建时传入的商户订单号 |

* 出参说明

可前往[alipay.trade.query](https://docs.open.alipay.com/api_1/alipay.trade.query)查看更加详细的参数说明。

### 交易退款
* API声明

refund(outTradeNo: string, refundAmount: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| outTradeNo | string | 是 | 交易创建时传入的商户订单号 |
| refundAmount | string | 是 | 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数 |

* 出参说明

可前往[alipay.trade.refund](https://docs.open.alipay.com/api_1/alipay.trade.refund)查看更加详细的参数说明。

### 关闭交易
* API声明

close(outTradeNo: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| outTradeNo | string | 是 | 交易创建时传入的商户订单号 |

* 出参说明

可前往[alipay.trade.close](https://docs.open.alipay.com/api_1/alipay.trade.close)查看更加详细的参数说明。

### 撤销交易
* API声明

cancel(outTradeNo: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| outTradeNo | string | 是 | 交易创建时传入的商户订单号 |

* 出参说明

可前往[alipay.trade.cancel](https://docs.open.alipay.com/api_1/alipay.trade.cancel)查看更加详细的参数说明。

### 交易退款查询
* API声明

queryRefund(outTradeNo: string, outRequestNo: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| outTradeNo | string | 是 | 交易创建时传入的商户订单号 |
| outRequestNo | string | 是 | 请求退款接口时,传入的退款请求号,如果在退款请求时未传入,则该值为创建交易时的外部交易号 |

* 出参说明

可前往[alipay.trade.fastpay.refund.query](https://opendocs.alipay.com/apis/api_1/alipay.trade.fastpay.refund.query)查看更加详细的参数说明。


### 查询对账单下载地址
* API声明

downloadBill(billType: string, billDate: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| billType | string | 是 | 账单类型商户通过接口或商户经开放平台授权后其所属服务商通过接口可以获取以下账单类型trade、signcustomertrade指商户基于支付宝交易收单的业务账单signcustomer是指基于商户支付宝余额收入及支出等资金变动的帐务账单 |
| billDate | string | 是 | 账单时间日账单格式为yyyy-MM-dd最早可下载2016年1月1日开始的日账单月账单格式为yyyy-MM最早可下载2016年1月开始的月账单 |

* 出参说明

可前往[alipay.data.dataservice.bill.downloadurl.query](https://opendocs.alipay.com/apis/api_15/alipay.data.dataservice.bill.downloadurl.query)查看更加详细的参数说明。


### 异步通知验签
* API声明

verifyNotify(parameters: map[string]string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| parameters | map[string]string | 是 | 异步通知中收到的待验签的所有参数 |

---

## 花呗分期 Huabei
### 创建花呗分期交易
* API声明

create(subject: string, outTradeNo: string, totalAmount: string, buyerId: string, extendParams: HuabeiConfig)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| subject | string | 是 | 订单标题 |
| outTradeNo | string | 是 | 商户订单号64个字符以内可包含字母、数字、下划线需保证在商户端不重复 |
| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] |
| buyerId | string | 是 | 买家的支付宝用户ID如果为空会从传入的码值信息中获取买家ID |
| extendParams | HuabeiConfig | 是 | 花呗交易扩展参数 |

HuabeiConfig对象说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| hbFqNum | string | 是 | 花呗分期数仅支持传入3、6、12 |
| hbFqSellerPercent | string | 是 | 代表卖家承担收费比例商家承担手续费传入100用户承担手续费传入0仅支持传入100、0两种 |


* 出参说明

可前往[alipay.trade.create](https://docs.open.alipay.com/api_1/alipay.trade.create)查看更加详细的参数说明。

---

<a name="faceToFace"/>

## 当面付 FaceToFace
### 当面付交易付款
* API声明

pay(subject: string, outTradeNo: string, totalAmount: string, authCode: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| subject | string | 是 | 订单标题 |
| outTradeNo | string | 是 | 交易创建时传入的商户订单号 |
| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] |
| authCode | string | 是 | 支付授权码,即买家的付款码数字 |

* 出参说明

可前往[alipay.trade.pay](https://docs.open.alipay.com/api_1/alipay.trade.pay)查看更加详细的参数说明。

* 返佣说明

ISV对接当面付产品需涉及返佣时请先阅读[政策详情](https://opendocs.alipay.com/p/00fc2g)与[合作攻略](https://opendocs.alipay.com/open/300/taphxd)。


**对接时必须在支付接口的extend_params参数中设置sys_service_provider_id返佣参数 参数值为签约返佣协议的PID**示例代码如下Java为例

```java
Map<String, String> extendParams = new HashMap<>();
extendParams.put("sys_service_provider_id", "<--请填写ISV签约协议的PID比如2088511833207846-->");
AlipayTradePayResponse response = Factory.Payment.FaceToFace()
.agent("<--请填写商户应用授权后获取到的app_auth_token比如ca34ea491e7146cc87d25fca24c4cD11-->")
.optional("extend_params", extendParams)
.pay("iPhone6 16G", "64628156-f784-4572-9540-485b7c91b850", "0.01", "289821051157962364");
```

---
### 交易预创建,生成正扫二维码
* API声明

precreate(subject: string, outTradeNo: string, totalAmount: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| subject | string | 是 | 订单标题 |
| outTradeNo | string | 是 | 交易创建时传入的商户订单号 |
| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] |

* 出参说明

可前往[alipay.trade.precreate](https://docs.open.alipay.com/api_1/alipay.trade.precreate)查看更加详细的参数说明。

* 返佣说明

ISV对接当面付产品需涉及返佣时请先阅读[政策详情](https://opendocs.alipay.com/p/00fc2g)与[合作攻略](https://opendocs.alipay.com/open/300/taphxd)。


**对接时必须在支付接口的extend_params参数中设置sys_service_provider_id返佣参数 参数值为签约返佣协议的PID**示例代码如下Java为例

```java
Map<String, String> extendParams = new HashMap<>();
extendParams.put("sys_service_provider_id", "<--请填写ISV签约协议的PID比如2088511833207846-->");
AlipayTradePrecreateResponse response = Payment.FaceToFace()
.agent("<--请填写商户应用授权后获取到的app_auth_token比如ca34ea491e7146cc87d25fca24c4cD11-->")
.optional("extend_params", extendParams)
.preCreate("iPhone6 16G", "64628156-f784-4572-9540-485b7c91b850", "0.01");
```

---
## 电脑网站 Page
### 电脑网站支付
* API声明

pay(subject: string, outTradeNo: string, totalAmount: string, returnUrl: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| subject | string | 是 | 订单标题 |
| outTradeNo | string | 是 | 交易创建时传入的商户订单号 |
| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] |
| returnUrl | string | 否 | 支付成功后同步跳转的页面是一个http/https开头的字符串 |

* 出参说明

可前往[alipay.trade.page.pay](https://docs.open.alipay.com/api_1/alipay.trade.page.pay)查看更加详细的参数说明。

---

## 手机网站 Wap
### 手机网站支付
* API声明

pay(subject: string, outTradeNo: string, totalAmount: string, quitUrl: string, returnUrl: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| subject | string | 是 | 订单标题 |
| outTradeNo | string | 是 | 交易创建时传入的商户订单号 |
| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] |
| quitUrl | string | 是 | 用户付款中途退出返回商户网站的地址 |
| returnUrl | string | 否 | 支付成功后同步跳转的页面是一个http/https开头的字符串 |

* 出参说明

可前往[alipay.trade.wap.pay](https://docs.open.alipay.com/api_1/alipay.trade.wap.pay)查看更加详细的参数说明。

---

## App支付 App
### 手机APP支付
* API声明

pay(subject: string, outTradeNo: string, totalAmount: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| subject | string | 是 | 订单标题 |
| outTradeNo | string | 是 | 交易创建时传入的商户订单号 |
| totalAmount | string | 是 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] |

* 出参说明

可前往[alipay.trade.app.pay](https://docs.open.alipay.com/api_1/alipay.trade.app.pay)查看更加详细的参数说明。

---

# 安全能力 Security
## 文本风险识别 TextRisk
### 检测内容风险
* API声明

detect(content: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| content | string | 是 | 待检测的文本内容 |

* 出参说明

可前往[alipay.security.risk.content.detect](https://docs.open.alipay.com/api_49/alipay.security.risk.content.detect)查看更加详细的参数说明。

---

# 辅助工具 Util


## 加解密 AES
### AES解密常用于会员手机号解密
* API声明

decrypt(cipherText: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| cipherText | string | 是 | 密文 |

* 出参说明

| 类型 | 说明 |
|------|----|
| string | 明文|

### AES加密
* API声明

encrypt(plainText: string)

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| plainText | string | 是 | 明文 |

* 出参说明

| 类型 | 说明 |
|------|----|
| string | 密文|


<a name="generic"/>

## 通用接口 Generic
### 执行OpenAPI调用
* API声明

execute(method: string, textParams: map[string]string, bizParams: map[string]any): AlipayOpenApiGenericResponse

* 接口说明

对于Alipay Easy SDK尚未支持的Open API开发者可以通过调用此方法通过自行拼装请求参数完成大部分OpenAPI的调用且调用时可按需设置所有可选参数。本接口同样会自动为您完成请求的加签和响应的验签工作。
注:本接口不支持文件型字段的上传。

* 入参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| method | string | 是 | OpenAPI的名称例如alipay.trade.pay |
| textParams | map[string]string | 否 | **没有**包装在`biz_content`下的请求参数集合,例如`app_auth_token`等参数 |
| bizParams | map[string]any | 否 | 被包装在`biz_content`下的请求参数集合 |

* 出参说明

| 字段名 | 类型 | 必填 | 说明 |
|------|--------|----|----|
| httpBody | string | 是 | 网关返回的HTTP响应是一个JSON格式的字符串开发者可按需从中解析出响应参数响应示例{"alipay_trade_create_response":{"code":"10000","msg":"Success","out_trade_no":"4ac9eac...","trade_no":"202003..."},"sign":"AUumfYgGSe7...02MA=="} |
| code | string | 是 | [网关返回码](https://docs.open.alipay.com/common/105806) |
| msg | string | 是 | [网关返回码描述](https://docs.open.alipay.com/common/105806) |
| subCode | string | 否 | 业务返回码参见具体的API接口文档 |
| subMsg | string | 否 | 业务返回码描述参见具体的API接口文档 |

---




View file

@ -1,182 +0,0 @@
最新变更
java删除Factory.getClient方法
php删除php中多余的composer包

Java版本
2022-05-06 Version: 2.2.2
1. 删除Factory.getClient方法

2021-09-04 Version: 2.2.1
1. 修复Okhttp Response没有主动关闭的问题。

2021-01-18 Version: 2.2.0
1. 增加sdkExecute功能。
2. 增加fileExecute功能。
3. 增加MultipleFactory多实例调用。

2020-12-11 Version: 2.1.2
1. 增加可设置ignoreSSL忽略SSL校验功能。

2020-09-23 Version: 2.1.0
1. 升级Tea版本降低对OkHttp的特性依赖提升环境兼容性。
2. 提供Factory.getClient方法用于调用SDK扩展包中的方法。

2020-08-18 Version: 2.0.2
1. 取消shade打包便于排除冲突依赖。

2020-07-06 Version: 2.0.1
1. 私钥支持阿里云KMS。

2020-06-09 Version: 2.0.0
1. 支持可选业务参数的装配。
2. 支持ISV代调用。
3. 提供ResponseChecker辅助工具类帮助校验响应是否成功。

2020-05-06 Version: 1.2.1
1. 手机网站支付、电脑网站支付接口支持设置return_url同步跳转地址。

2020-04-15 Version: 1.2.0
1. 扩展支持的支付类OpenAPI接口
Factory.Payment.Common().queryRefund 查询退款信息
Factory.Payment.Common().downloadBill 下载对账单
Factory.Payment.FaceToFace().preCreate 交易预创建,生成正扫二维码
Factory.Payment.Wap().pay 手机网站支付
Factory.Payment.Page().pay 电脑网站支付
Factory.Payment.App().pay 手机APP支付
2. 支持支付的异步通知及其验签
初始化Alipay Easy SDK的Config参数中新增notifyUrl参数用户可以统一配置自己的回调地址。
提供如下接口,完成支付类异步通知的验签。
Factory.Payment.Common().verifyNotify
3. AES加解密功能
Factory.Util.AES().decrypt 支持会员手机号AES解密
Factory.Util.AES().encrypt AES加密

2020-03-31 Version: 1.1.3
1. 去除SDK内置的logback.xml日志配置文件以免意外覆盖开发者项目主体工程的日志配置。

2020-03-27 Version: 1.1.2
1. 修复返回的响应中存在数组类型字段时反序列化成Response对象可能抛异常的问题。

2020-03-16 Version: 1.1.1
1. 修复证书路径不支持从CLASS_PATH中加载的问题。

2020-03-10 Version: 1.1.0
1. 添加兜底通用接口支持通过自行拼接请求参数完成几乎所有OpenAPI的调用。

2020-02-26 Version: 1.0.0
1. 首次发布。



C#版本
2020-12-11 Version: 2.1.3
1. 修复OpenAPI响应对象特殊情况下可能反序列化失败的异常。

2020-12-11 Version: 2.1.2
1. 增加可设置ignoreSSL忽略SSL校验功能。

2020-12-09 Version: 2.1.1
1. 增加httpProxy功能。

2020-09-23 Version: 2.1.0
1. 升级Tea版本。
2. 提供Factory.getClient方法用于调用SDK扩展包中的方法。

2020-08-18 Version: 2.0.1
1. 修复证书模式下异步验签异常的问题。

2020-06-09 Version: 2.0.0
1. 支持可选业务参数的装配。
2. 支持ISV代调用。
3. 提供ResponseChecker辅助工具类帮助校验响应是否成功。

2020-05-06 Version: 1.2.1
1. 手机网站支付、电脑网站支付接口支持设置return_url同步跳转地址。

2020-04-15 Version: 1.2.0
1. 扩展支持的支付类OpenAPI接口
Factory.Payment.Common().QueryRefund 查询退款信息
Factory.Payment.Common().DownloadBill 下载对账单
Factory.Payment.FaceToFace().PreCreate 交易预创建,生成正扫二维码
Factory.Payment.Wap().Pay 手机网站支付
Factory.Payment.Page().Pay 电脑网站支付
Factory.Payment.App().Pay 手机APP支付
2. 支持支付的异步通知及其验签
初始化Alipay Easy SDK的Config参数中新增notifyUrl参数用户可以统一配置自己的回调地址。
提供如下接口,完成支付类异步通知的验签。
Factory.Payment.Common().verifyNotify
3. AES加解密功能
Factory.Util.AES().Decrypt 支持会员手机号AES解密
Factory.Util.AES().Encrypt AES加密

2020-03-10 Version: 1.1.0
1. 添加兜底通用接口支持通过自行拼接请求参数完成几乎所有OpenAPI的调用。

2020-02-26 Version: 1.0.0
1. 首次发布。



PHP版本
2022-11-28 Version: 2.2.3
1、去掉多余引号
2、toMultipartRequestBody方法中PHP8时 0 != $readLength 永远为true导致while产生死循环

2022-05-06 Version: 2.2.2
1. php删除php中多余的composer包

2021-09-24 Version: 2.2.1
1. 修复PHP7.4及其以上环境下,根证书解析报错的问题。

2021-01-18 Version: 2.2.0
1. 增加sdkExecute功能。
2. 增加fileExecute功能。
3. 增加MultipleFactory多实例调用。


2020-12-11 Version: 2.0.3
1. 增加可设置ignoreSSL忽略SSL校验功能。

2020-12-09 Version: 2.0.2
1. 增加httpProxy功能。
2. 修复agent不生效问题。

2020-07-06 Version: 2.0.0
1. 支持可选业务参数的装配。
2. 支持ISV代调用。
3. 提供ResponseChecker辅助工具类帮助校验响应是否成功。

2020-05-06 Version: 1.2.1
1. 手机网站支付、电脑网站支付接口支持设置return_url同步跳转地址。

2020-04-15 Version: 1.2.0
1. 扩展支持的支付类OpenAPI接口
Factory::payment()->common()->queryRefund 查询退款信息
Factory::payment()->common()->downloadBill 下载对账单
Factory::payment()->faceToFace()->preCreate 交易预创建,生成正扫二维码
Factory::payment()->wap()->pay 手机网站支付
Factory::payment()->page()->pay 电脑网站支付
Factory::payment()->app()->pay 手机APP支付
2. 支持支付的异步通知及其验签
初始化Alipay Easy SDK的Config参数中新增notifyUrl参数用户可以统一配置自己的回调地址。
提供如下接口,完成支付类异步通知的验签。
Factory::payment()->common()->verifyNotify
3. AES加解密功能
Factory::util()->aes()->decrypt 支持会员手机号AES解密
Factory::util()->aes()->encrypt AES加密
4. 重构api的respone模型返回格式与Java、Net保持一致

2020-03-27 Version: 1.1.0
1. 修复大小写路径敏感问题。

2020-03-20 Version: 1.0.0
1. 首次发布。


PHP版本
2021-09-24 Version: 2.0.1
1.修复PHP7.4及其以上环境下,根证书解析报错的问题。

2021-01-18 Version: 1.0.0
1. 首次发布。

View file

@ -1,21 +0,0 @@
MIT License

Copyright (c) 2020 Ant Small and Micro Financial Services Group Co., Ltd.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,203 +0,0 @@
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk?ref=badge_shield)
[![Maven Central](https://img.shields.io/maven-central/v/com.alipay.sdk/alipay-easysdk.svg)](https://mvnrepository.com/artifact/com.alipay.sdk/alipay-easysdk)
[![NuGet](https://badge.fury.io/nu/AlipayEasySDK.svg)](https://badge.fury.io/nu/AlipayEasySDK)
[![Packagist](https://poser.pugx.org/alipaysdk/easysdk/v/stable)](https://packagist.org/packages/alipaysdk/easysdk)

欢迎使用 Alipay **Easy** SDK。

打造**最好用**的支付宝开放平台**服务端SDK**Alipay Easy SDK让您享受**极简编程**体验,快速访问支付宝开放平台开放的各项**核心能力**。

## 设计理念
不同于原有的Alipay SDK通用而全面的设计理念Alipay Easy SDK对开放能力的API进行了更加贴近高频场景的精心设计与裁剪简化了服务端调用方式让调用API像使用语言内置的函数一样简便。

同时您也不必担心面向高频场景提炼的API可能无法完全契合自己的个性化场景Alipay Easy SDK支持灵活的[动态扩展](#extension)方式同样可以满足低频参数、低频API的使用需求。

Alipay Easy SDK提供了与[能力地图](https://opendocs.alipay.com/mini/00am3f)相对应的代码组织结构让开发者可以快速找到不同能力对应的API。

Alipay Easy SDK主要目标是提升开发者在**服务端**集成支付宝开放平台开放的各类核心能力的效率。

### 化繁为简

| Alipay Easy SDK | Alipay SDK |
|------------------|----------------------------------------------------------------|
| 极简代码风格,更贴近自然语言阅读习惯 | 传统代码风格,需要多行代码完成一个接口的调用 |
| Factory单例全局任何地方都可直接引用 | AlipayClient实例需自行创建并在上下文中传递 |
| API中只保留高频场景下的必备参数同时提供低频可选参数的装配能力 | 没有区分高低频参数单API最多可达数十个入参对普通开发者的干扰较大 |


* Alipay Easy SDK :smiley:

```java
Factory.Payment.Common().create("Iphone6 16G", "202003019443", "0.10", "2088002656718920");
```

* Alipay SDK :confused:

```java
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();

AlipayTradeCreateModel model = new AlipayTradeCreateModel();
model.setSubject("Iphone6 16G");
model.setOutTradeNo("202003019443");
model.setTotalAmount("0.10");
model.setBuyerId("2088002656718920");
...

request.setBizModel(model);
...

alipayClient.execute(request);
```

### 如何切换
* 无论是Alipay Easy SDK还是Alipay SDK本质都是发送HTTP请求访问Open API网关所以只需将原来通过Alipay SDK调用Open API的代码替换为Alipay Easy SDK中对应API的调用即可。Alipay Easy SDK和Alipay SDK并无冲突可以共存。

* 如果您所需对接的开放平台能力Alipay Easy SDK尚未提炼出API支持[已支持的API列表](#apiList)),您可以通过[通用接口](./APIDoc.md#generic)完成调用。

* 我们会持续挖掘高频场景不断丰富Alipay Easy SDK支持的API让您在绝大多数常见场景下都能享受Alipay Easy SDK带来的便捷。

## 技术特点
### 纯语言开发
所有Alipay Easy SDK的具体编程语言的实现均只采用纯编程语言进行开发不引入任何重量级框架减少潜在的框架冲突让SDK可以自由集成进任何代码环境中。

### 结构清晰
我们按照能力类别和场景类别对API进行了归类结构更加清晰一目了然。
> 更多信息请参见[API组织规范](#spec)。

### 参数精简
Alipay Easy SDK对每个API都精心打磨剔除了`Open API`中不常用的可选参数,减少普通用户的无效选择,提升开发效率。

<a name="extension"/>

### 灵活扩展
开发者可以通过Fluent风格的API链式调用在为高频场景打造的API基础上不断扩展自己的个性化场景需求。

```java
// 通过调用agent方法扩展支持ISV代调用场景
Factory.Payment.FaceToFace().agent("ca34ea491e7146cc87d25fca24c4cD11").preCreate(...)

// 通过调用optional方法扩展支持个性化可选参数
Factory.Payment.FaceToFace().optional("extend_params", extendParams).preCreate(...)

// 多种扩展可灵活搭配,不同扩展方法功能详细说明请前往各语言主页中的“快速开始-扩展调用”栏目中查看
Factory.Payment.FaceToFace()
.agent(...)
.optionalArgs(...)
.auth(...)
.asyncNotify(...)
.preCreate(...)
```

### 测试/示例完备
每个API都有对应的单元测试进行覆盖良好的单元测试天生就是最好的示例。

同时您也可以前往[API Doc](./APIDoc.md)查看每个API的详细使用说明。

> 注:单元测试中使用到的私钥均进行了脱敏处理,会导致单元测试无法直接执行。您可以自行更改单元测试项目中的`TestAccout类`和`privateKey.json`文件中的相关账号与私钥配置后再执行单元测试。

### 多语言
Alipay Easy SDK基于阿里集团研发的[`Darabonba`](https://github.com/aliyun/darabonba)进行架构通过DSL中间语言定义API模型再基于DSL语言自动生成不同编程语言Java、C#、PHP、TS等实现的SDK极大地提升了SDK能力的扩展效率和适用范围同时也保证了相同的`Easy API`在不同语言生态中体验的一致性。

API模型的DSL描述可以进入[tea](./tea)目录查看。

### 快速集成
各语言SDK均会在各自的中央仓库Maven、NuGet、Composer、NPM etc.中同步发布让您使用各语言主流依赖管理工具即可一键安装集成SDK。

## 语言支持情况
Alipay Easy SDK首发暂只支持`Java`、`C#`、`PHP`编程语言,更多编程语言支持正在积极新增中,敬请期待。

各语言具体的**使用说明**和**详细介绍**请点击如下链接进入各语言主目录查看。

[Java](./java)

[C#](./csharp)

[PHP](./php)

<a name="spec"/>

## API组织规范

在Alipay Easy SDK中API的引用路径与能力地图的组织层次一致遵循如下规范

> Factory.能力类别.场景类别.接口方法名称( ... )

比如,如果您想要使用[能力地图](https://opendocs.alipay.com/mini/00am3f)中`营销能力`下的`模板消息`场景中的`小程序发送模板消息`,只需按如下形式编写调用代码即可(不同编程语言的连接符号可能不同)。

`Factory.Marketing.TemplateMessage().send( ... )`

其中接口方法名称通常是对其依赖的OpenAPI功能的一个最简概况接口方法的出入参与OpenAPI中同名参数含义一致可参照OpenAPI相关参数的使用说明。

Alipay Easy SDK将致力于保持良好的API命名以符合开发者的编程直觉。

<a name="apiList"/>

## 已支持的API列表

| 能力类别 | 场景类别 | 接口方法名称 | 调用的OpenAPI名称 |
|-----------|-----------------|------------------------|-----------------------------------------------------------|
| Base<br/>基础能力 | OAuth<br/>用户授权 | getToken<br/>获取授权访问令牌和用户user_id | alipay\.system\.oauth\.token |
| Base<br/>基础能力 | OAuth<br/>用户授权 | refreshToken<br/>刷新授权访问令牌 | alipay\.system\.oauth\.token |
| Base<br/>基础能力 | Qrcode<br/>小程序二维码 | create<br/>创建小程序二维码 | alipay\.open\.app\.qrcode\.create |
| Base<br/>基础能力 | Image<br/>图片 | upload<br/>上传门店照片 | alipay\.offline\.material\.image\.upload |
| Base<br/>基础能力 | Video<br/>视频 | upload<br/>上传门店视频 | alipay\.offline\.material\.image\.upload |
| Member<br/>会员能力 | Identification<br/>支付宝身份认证 | init<br/>身份认证初始化 | alipay\.user\.certify\.open\.initialize |
| Member<br/>会员能力 | Identification<br/>支付宝身份认证 | certify<br/>生成认证链接 | alipay\.user\.certify\.open\.certify |
| Member<br/>会员能力 | Identification<br/>支付宝身份认证 | query<br/>身份认证记录查询 | alipay\.user\.certify\.open\.query |
| Payment<br/>支付能力 | Common<br/>通用 | create<br/>创建交易 | alipay\.trade\.create |
| Payment<br/>支付能力 | Common<br/>通用 | query<br/>查询交易 | alipay\.trade\.query |
| Payment<br/>支付能力 | Common<br/>通用 | refund<br/>交易退款 | alipay\.trade\.refund |
| Payment<br/>支付能力 | Common<br/>通用 | close<br/>关闭交易 | alipay\.trade\.close |
| Payment<br/>支付能力 | Common<br/>通用 | cancel<br/>撤销交易 | alipay\.trade\.cancel |
| Payment<br/>支付能力 | Common<br/>通用 | queryRefund<br/>交易退款查询 | alipay\.trade\.fastpay\.refund\.query |
| Payment<br/>支付能力 | Common<br/>通用 | downloadBill<br/>查询对账单下载地址 | alipay\.data\.dataservice\.bill\.downloadurl\.query |
| Payment<br/>支付能力 | Common<br/>通用 | verifyNotify<br/>异步通知验签 | - |
| Payment<br/>支付能力 | Huabei<br/>花呗分期 | create<br/>创建花呗分期交易 | alipay\.trade\.create |
| Payment<br/>支付能力 | FaceToFace<br/>当面付 | pay<br/>扫用户出示的付款码,完成付款 | alipay\.trade\.pay |
| Payment<br/>支付能力 | FaceToFace<br/>当面付 | precreate<br/>生成交易付款码,待用户扫码付款 | alipay\.trade\.precreate |
| Payment<br/>支付能力 | App<br/>手机APP | pay<br/>生成订单串,再使用客户端 SDK 凭此串唤起支付宝收银台 | alipay\.trade\.app\.pay |
| Payment<br/>支付能力 | Page<br/>电脑网站 | pay<br/>生成交易表单,渲染后自动跳转支付宝网站引导用户完成支付 | alipay\.trade\.page\.pay |
| Payment<br/>支付能力 | Wap<br/>手机网站 | pay<br/>生成交易表单,渲染后自动跳转支付宝网站引导用户完成支付 | alipay\.trade\.wap\.pay |
| Security<br/>安全能力 | TextRisk<br/>文本内容安全 | detect<br/>检测内容风险 | alipay\.security\.risk\.content\.detect |
| Marketing<br/>营销能力 | Pass<br/>支付宝卡包 | createTemplate<br/>卡券模板创建 | alipay\.pass\.template\.add |
| Marketing<br/>营销能力 | Pass<br/>支付宝卡包 | updateTemplate<br/>卡券模板更新 | alipay\.pass\.template\.update |
| Marketing<br/>营销能力 | Pass<br/>支付宝卡包 | addInstance<br/>卡券实例发放 | alipay\.pass\.instance\.add |
| Marketing<br/>营销能力 | Pass<br/>支付宝卡包 | updateInstance<br/>卡券实例更新 | alipay\.pass\.instance\.update |
| Marketing<br/>营销能力 | TemplateMessage<br/>小程序模板消息 | send <br/>发送模板消息| alipay\.open\.app\.mini\.templatemessage\.send |
| Marketing<br/>营销能力 | OpenLife<br/>生活号 | createImageTextContent<br/>创建图文消息内容 | alipay\.open\.public\.message\.content\.create |
| Marketing<br/>营销能力 | OpenLife<br/>生活号 | modifyImageTextContent<br/>更新图文消息内容 | alipay\.open\.public\.message\.content\.modify |
| Marketing<br/>营销能力 | OpenLife<br/>生活号 | sendText<br/>群发本文消息 | alipay\.open\.public\.message\.total\.send |
| Marketing<br/>营销能力 | OpenLife<br/>生活号 | sendImageText<br/>群发图文消息 | alipay\.open\.public\.message\.total\.send |
| Marketing<br/>营销能力 | OpenLife<br/>生活号 | sendSingleMessage<br/>单发模板消息 | alipay\.open\.public\.message\.single\.send |
| Marketing<br/>营销能力 | OpenLife<br/>生活号 | recallMessage<br/>生活号消息撤回 | alipay\.open\.public\.life\.msg\.recall |
| Marketing<br/>营销能力 | OpenLife<br/>生活号 | setIndustry<br/>模板消息行业设置 | alipay\.open\.public\.template\.message\.industry\.modify |
| Marketing<br/>营销能力 | OpenLife<br/>生活号 | getIndustry<br/>生活号查询行业设置 | alipay\.open\.public\.setting\.category\.query |
| Util<br/>辅助工具 | AES<br/>加解密 | decrypt<br/>解密,常用于会员手机号解密 | - |
| Util<br/>辅助工具 | AES<br/>加解密 | encrypt<br/>加密 | - |
| Util<br/>辅助工具 | Generic<br/>通用接口 | execute<br/>自行拼接参数执行OpenAPI调用 | - |

> 注更多高频场景的API持续更新中敬请期待。

您还可以前往[API Doc](./APIDoc.md)查看每个API的详细使用说明。

# 变更日志
每个版本的详细更改记录在[变更日志](./CHANGELOG)中。

> 版本号最末一位修订号的增加(比如从`1.0.0`升级为`1.0.1`意味着SDK的功能没有发生任何变化仅仅是修复了部分Bug。该类升级可能不会记录在变更日志中。

> 版本号中间一位次版本号的增加(比如从`1.0.0`升级为`1.1.0`意味着SDK的功能发生了可向下兼容的新增或修改。

> 版本号首位主版本号的增加(比如从`1.0.0`升级为`2.0.0`意味着SDK的功能可能发生了不向下兼容的较大调整升级主版本号后请注意做好相关的回归测试工作。

# 相关
* [支付宝开放平台](https://open.alipay.com/platform/home.htm)
* [支付宝开放平台文档中心](https://docs.open.alipay.com/catalog)
* [最新源码](https://github.com/alipay/alipay-easysdk)

# 许可证
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Falipay%2Falipay-easysdk?ref=badge_large)

# 交流与技术支持
不管您在使用Alipay Easy SDK的过程中遇到任何问题欢迎前往 [支付宝开放社区](https://forum.alipay.com/mini-app/channel/1100001) 发帖与支付宝工作人员和其他开发者一起交流。

为了提高开发者问题的响应时效github本身的issue功能已关闭支付宝开放社区中发帖的问题通常会在2小时内响应。

View file

@ -1,49 +0,0 @@
{
"name":"alipaysdk/easysdk",
"description":"支付宝官方 Alipay Easy SDK",
"type":"library",
"version":"2.2.3",
"authors":[
{
"name":"junying.wjy",
"email":"junying.wjy@antfin.com"
}
],
"autoload":{
"psr-4":{
"Alipay\\EasySDK\\":"php/src/"
}
},
"autoload-dev": {
"psr-4": {
"Alipay\\EasySDK\\Test\\": "php/test/"
}
},
"license":"Apache-2.0",
"minimum-stability":"dev",
"require":{
"php": ">=7.0",
"ext-curl":"*",
"ext-ctype":"*",
"ext-dom":"*",
"ext-fileinfo": "*",
"ext-json":"*",
"ext-libxml":"*",
"ext-simplexml":"*",
"ext-mbstring":"*",
"ext-openssl":"*",
"ext-xmlwriter": "*",
"guzzlehttp/guzzle":">=6.3",
"alibabacloud/tea": "^3.1",
"alibabacloud/tea-fileform": "^0.3.2"
},
"require-dev": {
"phpunit/phpunit": "^7.5"
},
"repositories":{
"packagist":{
"type":"composer",
"url":"https://mirrors.aliyun.com/composer/"
}
}
}

View file

@ -1,23 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlipayEasySDK", "AlipayEasySDK\AlipayEasySDK.csproj", "{14B089B9-C61C-46E6-BD93-5DFBBB77E2B2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTest", "UnitTest\UnitTest.csproj", "{79DE080D-34C1-485E-996D-435A8515766D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{14B089B9-C61C-46E6-BD93-5DFBBB77E2B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14B089B9-C61C-46E6-BD93-5DFBBB77E2B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14B089B9-C61C-46E6-BD93-5DFBBB77E2B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14B089B9-C61C-46E6-BD93-5DFBBB77E2B2}.Release|Any CPU.Build.0 = Release|Any CPU
{79DE080D-34C1-485E-996D-435A8515766D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{79DE080D-34C1-485E-996D-435A8515766D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{79DE080D-34C1-485E-996D-435A8515766D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79DE080D-34C1-485E-996D-435A8515766D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View file

@ -1,32 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
<PackOnBuild>true</PackOnBuild>
<PackageVersion>2.1.3</PackageVersion>
<Authors>antopen</Authors>
<NeutralLanguage>zh</NeutralLanguage>
<PackageLicenseUrl>https://github.com/alipay/alipay-easysdk/blob/master/LICENSE</PackageLicenseUrl>
<Description>Alipay Easy SDK for .NET allows you to enjoy a minimalist programming experience and quickly access the various high-frequency capabilities of the Alipay Open Platform.</Description>
<PackageId>AlipayEasySDK</PackageId>
<Owners>antopen</Owners>
<PackageProjectUrl>https://github.com/alipay/alipay-easysdk/tree/master/csharp</PackageProjectUrl>
<Summary>Alipay Easy SDK for .NET allows you to enjoy a minimalist programming experience and quickly access the various high-frequency capabilities of the Alipay Open Platform.</Summary>
<Title>Alipay Easy SDK</Title>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType></DebugType>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Class1.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Factory\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AlipayEasySDK.Kernel" Version="1.0.6" />
</ItemGroup>
</Project>

View file

@ -1,324 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

using Tea;
using Tea.Utils;

using Alipay.EasySDK.Base.Image.Models;

namespace Alipay.EasySDK.Base.Image
{
public class Client
{
protected Alipay.EasySDK.Kernel.Client _kernel;

public Client(Alipay.EasySDK.Kernel.Client kernel)
{
this._kernel = kernel;
}

public AlipayOfflineMaterialImageUploadResponse Upload(string imageName, string imageFilePath)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 100000},
{"readTimeout", 100000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.offline.material.image.upload"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>(){};
Dictionary<string, string> textParams = new Dictionary<string, string>
{
{"image_type", "jpg"},
{"image_name", imageName},
};
Dictionary<string, string> fileParams = new Dictionary<string, string>
{
{"image_content", imageFilePath},
};
string boundary = this._kernel.GetRandomBoundary();
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", this._kernel.ConcatStr("multipart/form-data;charset=utf-8;boundary=", boundary)},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams
));
request_.Body = this._kernel.ToMultipartRequestBody(textParams, fileParams, boundary);
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.offline.material.image.upload");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayOfflineMaterialImageUploadResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayOfflineMaterialImageUploadResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipayOfflineMaterialImageUploadResponse> UploadAsync(string imageName, string imageFilePath)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 100000},
{"readTimeout", 100000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.offline.material.image.upload"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>(){};
Dictionary<string, string> textParams = new Dictionary<string, string>
{
{"image_type", "jpg"},
{"image_name", imageName},
};
Dictionary<string, string> fileParams = new Dictionary<string, string>
{
{"image_content", imageFilePath},
};
string boundary = this._kernel.GetRandomBoundary();
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", this._kernel.ConcatStr("multipart/form-data;charset=utf-8;boundary=", boundary)},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams
));
request_.Body = this._kernel.ToMultipartRequestBody(textParams, fileParams, boundary);
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.offline.material.image.upload");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayOfflineMaterialImageUploadResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayOfflineMaterialImageUploadResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

/// <summary>
/// ISV代商户代用指定appAuthToken
/// </summary>
/// <param name="appAuthToken">代调用token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Agent(string appAuthToken)
{
_kernel.InjectTextParam("app_auth_token", appAuthToken);
return this;
}

/// <summary>
/// 用户授权调用指定authToken
/// </summary>
/// <param name="authToken">用户授权token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Auth(string authToken)
{
_kernel.InjectTextParam("auth_token", authToken);
return this;
}

/// <summary>
/// 设置异步通知回调地址此处设置将在本调用中覆盖Config中的全局配置
/// </summary>
/// <param name="url">异步通知回调地址例如https://www.test.com/callback </param>
/// <returns>本客户端,便于链式调用</returns>
public Client AsyncNotify(string url)
{
_kernel.InjectTextParam("notify_url", url);
return this;
}

/// <summary>
/// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效
/// </summary>
/// <param name="testUrl">后端系统测试地址</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Route(string testUrl)
{
_kernel.InjectTextParam("ws_service_url", testUrl);
return this;
}

/// <summary>
/// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// </summary>
/// <param name="key">业务请求参数名称biz_content下的字段名比如timeout_express</param>
/// <param name="value">
/// 业务请求参数的值一个可以序列化成JSON的对象
/// 如果该字段是一个字符串类型String、Price、Date在SDK中都是字符串请使用string储存
/// 如果该字段是一个数值型类型比如Number请使用long储存
/// 如果该字段是一个复杂类型请使用嵌套的Dictionary指定各下级字段的值
/// 如果该字段是一个数组请使用List储存各个值
/// 对于更复杂的情况也支持Dictionary和List的各种组合嵌套比如参数是值是个ListList中的每种类型是一个复杂对象
/// </param>
/// <returns>本客户端,便于链式调用</returns>
public Client Optional(string key, object value)
{
_kernel.InjectBizParam(key, value);
return this;
}

/// <summary>
/// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// optional方法的批量版本
/// </summary>
/// <param name="optionalArgs">可选参数集合每个参数由key和value组成key和value的格式请参见optional方法的注释</param>
/// <returns>本客户端,便于链式调用</returns>
public Client BatchOptional(Dictionary<string, object> optionalArgs)
{
foreach (var pair in optionalArgs)
{
_kernel.InjectBizParam(pair.Key, pair.Value);
}
return this;
}
}
}

View file

@ -1,45 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Base.Image.Models
{
public class AlipayOfflineMaterialImageUploadResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("image_id")]
[Validation(Required=true)]
public string ImageId { get; set; }

[NameInMap("image_url")]
[Validation(Required=true)]
public string ImageUrl { get; set; }

}

}

View file

@ -1,528 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

using Tea;
using Tea.Utils;

using Alipay.EasySDK.Base.OAuth.Models;

namespace Alipay.EasySDK.Base.OAuth
{
public class Client
{
protected Alipay.EasySDK.Kernel.Client _kernel;

public Client(Alipay.EasySDK.Kernel.Client kernel)
{
this._kernel = kernel;
}

public AlipaySystemOauthTokenResponse GetToken(string code)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.system.oauth.token"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>(){};
Dictionary<string, string> textParams = new Dictionary<string, string>
{
{"grant_type", "authorization_code"},
{"code", code},
};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.system.oauth.token");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipaySystemOauthTokenResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipaySystemOauthTokenResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipaySystemOauthTokenResponse> GetTokenAsync(string code)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.system.oauth.token"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>(){};
Dictionary<string, string> textParams = new Dictionary<string, string>
{
{"grant_type", "authorization_code"},
{"code", code},
};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.system.oauth.token");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipaySystemOauthTokenResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipaySystemOauthTokenResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public AlipaySystemOauthTokenResponse RefreshToken(string refreshToken)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.system.oauth.token"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>(){};
Dictionary<string, string> textParams = new Dictionary<string, string>
{
{"grant_type", "refresh_token"},
{"refresh_token", refreshToken},
};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.system.oauth.token");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipaySystemOauthTokenResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipaySystemOauthTokenResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipaySystemOauthTokenResponse> RefreshTokenAsync(string refreshToken)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.system.oauth.token"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>(){};
Dictionary<string, string> textParams = new Dictionary<string, string>
{
{"grant_type", "refresh_token"},
{"refresh_token", refreshToken},
};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.system.oauth.token");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipaySystemOauthTokenResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipaySystemOauthTokenResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

/// <summary>
/// ISV代商户代用指定appAuthToken
/// </summary>
/// <param name="appAuthToken">代调用token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Agent(string appAuthToken)
{
_kernel.InjectTextParam("app_auth_token", appAuthToken);
return this;
}

/// <summary>
/// 用户授权调用指定authToken
/// </summary>
/// <param name="authToken">用户授权token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Auth(string authToken)
{
_kernel.InjectTextParam("auth_token", authToken);
return this;
}

/// <summary>
/// 设置异步通知回调地址此处设置将在本调用中覆盖Config中的全局配置
/// </summary>
/// <param name="url">异步通知回调地址例如https://www.test.com/callback </param>
/// <returns>本客户端,便于链式调用</returns>
public Client AsyncNotify(string url)
{
_kernel.InjectTextParam("notify_url", url);
return this;
}

/// <summary>
/// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效
/// </summary>
/// <param name="testUrl">后端系统测试地址</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Route(string testUrl)
{
_kernel.InjectTextParam("ws_service_url", testUrl);
return this;
}

/// <summary>
/// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// </summary>
/// <param name="key">业务请求参数名称biz_content下的字段名比如timeout_express</param>
/// <param name="value">
/// 业务请求参数的值一个可以序列化成JSON的对象
/// 如果该字段是一个字符串类型String、Price、Date在SDK中都是字符串请使用string储存
/// 如果该字段是一个数值型类型比如Number请使用long储存
/// 如果该字段是一个复杂类型请使用嵌套的Dictionary指定各下级字段的值
/// 如果该字段是一个数组请使用List储存各个值
/// 对于更复杂的情况也支持Dictionary和List的各种组合嵌套比如参数是值是个ListList中的每种类型是一个复杂对象
/// </param>
/// <returns>本客户端,便于链式调用</returns>
public Client Optional(string key, object value)
{
_kernel.InjectBizParam(key, value);
return this;
}

/// <summary>
/// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// optional方法的批量版本
/// </summary>
/// <param name="optionalArgs">可选参数集合每个参数由key和value组成key和value的格式请参见optional方法的注释</param>
/// <returns>本客户端,便于链式调用</returns>
public Client BatchOptional(Dictionary<string, object> optionalArgs)
{
foreach (var pair in optionalArgs)
{
_kernel.InjectBizParam(pair.Key, pair.Value);
}
return this;
}
}
}

View file

@ -1,57 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Base.OAuth.Models
{
public class AlipaySystemOauthTokenResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("user_id")]
[Validation(Required=true)]
public string UserId { get; set; }

[NameInMap("access_token")]
[Validation(Required=true)]
public string AccessToken { get; set; }

[NameInMap("expires_in")]
[Validation(Required=true)]
public long ExpiresIn { get; set; }

[NameInMap("refresh_token")]
[Validation(Required=true)]
public string RefreshToken { get; set; }

[NameInMap("re_expires_in")]
[Validation(Required=true)]
public long ReExpiresIn { get; set; }

}

}

View file

@ -1,318 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

using Tea;
using Tea.Utils;

using Alipay.EasySDK.Base.Qrcode.Models;

namespace Alipay.EasySDK.Base.Qrcode
{
public class Client
{
protected Alipay.EasySDK.Kernel.Client _kernel;

public Client(Alipay.EasySDK.Kernel.Client kernel)
{
this._kernel = kernel;
}

public AlipayOpenAppQrcodeCreateResponse Create(string urlParam, string queryParam, string describe)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.open.app.qrcode.create"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"url_param", urlParam},
{"query_param", queryParam},
{"describe", describe},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.open.app.qrcode.create");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayOpenAppQrcodeCreateResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayOpenAppQrcodeCreateResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipayOpenAppQrcodeCreateResponse> CreateAsync(string urlParam, string queryParam, string describe)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.open.app.qrcode.create"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"url_param", urlParam},
{"query_param", queryParam},
{"describe", describe},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.app.qrcode.create");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayOpenAppQrcodeCreateResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayOpenAppQrcodeCreateResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

/// <summary>
/// ISV代商户代用指定appAuthToken
/// </summary>
/// <param name="appAuthToken">代调用token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Agent(string appAuthToken)
{
_kernel.InjectTextParam("app_auth_token", appAuthToken);
return this;
}

/// <summary>
/// 用户授权调用指定authToken
/// </summary>
/// <param name="authToken">用户授权token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Auth(string authToken)
{
_kernel.InjectTextParam("auth_token", authToken);
return this;
}

/// <summary>
/// 设置异步通知回调地址此处设置将在本调用中覆盖Config中的全局配置
/// </summary>
/// <param name="url">异步通知回调地址例如https://www.test.com/callback </param>
/// <returns>本客户端,便于链式调用</returns>
public Client AsyncNotify(string url)
{
_kernel.InjectTextParam("notify_url", url);
return this;
}

/// <summary>
/// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效
/// </summary>
/// <param name="testUrl">后端系统测试地址</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Route(string testUrl)
{
_kernel.InjectTextParam("ws_service_url", testUrl);
return this;
}

/// <summary>
/// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// </summary>
/// <param name="key">业务请求参数名称biz_content下的字段名比如timeout_express</param>
/// <param name="value">
/// 业务请求参数的值一个可以序列化成JSON的对象
/// 如果该字段是一个字符串类型String、Price、Date在SDK中都是字符串请使用string储存
/// 如果该字段是一个数值型类型比如Number请使用long储存
/// 如果该字段是一个复杂类型请使用嵌套的Dictionary指定各下级字段的值
/// 如果该字段是一个数组请使用List储存各个值
/// 对于更复杂的情况也支持Dictionary和List的各种组合嵌套比如参数是值是个ListList中的每种类型是一个复杂对象
/// </param>
/// <returns>本客户端,便于链式调用</returns>
public Client Optional(string key, object value)
{
_kernel.InjectBizParam(key, value);
return this;
}

/// <summary>
/// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// optional方法的批量版本
/// </summary>
/// <param name="optionalArgs">可选参数集合每个参数由key和value组成key和value的格式请参见optional方法的注释</param>
/// <returns>本客户端,便于链式调用</returns>
public Client BatchOptional(Dictionary<string, object> optionalArgs)
{
foreach (var pair in optionalArgs)
{
_kernel.InjectBizParam(pair.Key, pair.Value);
}
return this;
}
}
}

View file

@ -1,41 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Base.Qrcode.Models
{
public class AlipayOpenAppQrcodeCreateResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("qr_code_url")]
[Validation(Required=true)]
public string QrCodeUrl { get; set; }

}

}

View file

@ -1,324 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

using Tea;
using Tea.Utils;

using Alipay.EasySDK.Base.Video.Models;

namespace Alipay.EasySDK.Base.Video
{
public class Client
{
protected Alipay.EasySDK.Kernel.Client _kernel;

public Client(Alipay.EasySDK.Kernel.Client kernel)
{
this._kernel = kernel;
}

public AlipayOfflineMaterialImageUploadResponse Upload(string videoName, string videoFilePath)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 100000},
{"readTimeout", 100000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.offline.material.image.upload"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>(){};
Dictionary<string, string> textParams = new Dictionary<string, string>
{
{"image_type", "mp4"},
{"image_name", videoName},
};
Dictionary<string, string> fileParams = new Dictionary<string, string>
{
{"image_content", videoFilePath},
};
string boundary = this._kernel.GetRandomBoundary();
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", this._kernel.ConcatStr("multipart/form-data;charset=utf-8;boundary=", boundary)},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams
));
request_.Body = this._kernel.ToMultipartRequestBody(textParams, fileParams, boundary);
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.offline.material.image.upload");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayOfflineMaterialImageUploadResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayOfflineMaterialImageUploadResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipayOfflineMaterialImageUploadResponse> UploadAsync(string videoName, string videoFilePath)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 100000},
{"readTimeout", 100000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.offline.material.image.upload"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>(){};
Dictionary<string, string> textParams = new Dictionary<string, string>
{
{"image_type", "mp4"},
{"image_name", videoName},
};
Dictionary<string, string> fileParams = new Dictionary<string, string>
{
{"image_content", videoFilePath},
};
string boundary = this._kernel.GetRandomBoundary();
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", this._kernel.ConcatStr("multipart/form-data;charset=utf-8;boundary=", boundary)},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams
));
request_.Body = this._kernel.ToMultipartRequestBody(textParams, fileParams, boundary);
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.offline.material.image.upload");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayOfflineMaterialImageUploadResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayOfflineMaterialImageUploadResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

/// <summary>
/// ISV代商户代用指定appAuthToken
/// </summary>
/// <param name="appAuthToken">代调用token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Agent(string appAuthToken)
{
_kernel.InjectTextParam("app_auth_token", appAuthToken);
return this;
}

/// <summary>
/// 用户授权调用指定authToken
/// </summary>
/// <param name="authToken">用户授权token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Auth(string authToken)
{
_kernel.InjectTextParam("auth_token", authToken);
return this;
}

/// <summary>
/// 设置异步通知回调地址此处设置将在本调用中覆盖Config中的全局配置
/// </summary>
/// <param name="url">异步通知回调地址例如https://www.test.com/callback </param>
/// <returns>本客户端,便于链式调用</returns>
public Client AsyncNotify(string url)
{
_kernel.InjectTextParam("notify_url", url);
return this;
}

/// <summary>
/// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效
/// </summary>
/// <param name="testUrl">后端系统测试地址</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Route(string testUrl)
{
_kernel.InjectTextParam("ws_service_url", testUrl);
return this;
}

/// <summary>
/// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// </summary>
/// <param name="key">业务请求参数名称biz_content下的字段名比如timeout_express</param>
/// <param name="value">
/// 业务请求参数的值一个可以序列化成JSON的对象
/// 如果该字段是一个字符串类型String、Price、Date在SDK中都是字符串请使用string储存
/// 如果该字段是一个数值型类型比如Number请使用long储存
/// 如果该字段是一个复杂类型请使用嵌套的Dictionary指定各下级字段的值
/// 如果该字段是一个数组请使用List储存各个值
/// 对于更复杂的情况也支持Dictionary和List的各种组合嵌套比如参数是值是个ListList中的每种类型是一个复杂对象
/// </param>
/// <returns>本客户端,便于链式调用</returns>
public Client Optional(string key, object value)
{
_kernel.InjectBizParam(key, value);
return this;
}

/// <summary>
/// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// optional方法的批量版本
/// </summary>
/// <param name="optionalArgs">可选参数集合每个参数由key和value组成key和value的格式请参见optional方法的注释</param>
/// <returns>本客户端,便于链式调用</returns>
public Client BatchOptional(Dictionary<string, object> optionalArgs)
{
foreach (var pair in optionalArgs)
{
_kernel.InjectBizParam(pair.Key, pair.Value);
}
return this;
}
}
}

View file

@ -1,45 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Base.Video.Models
{
public class AlipayOfflineMaterialImageUploadResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("image_id")]
[Validation(Required=true)]
public string ImageId { get; set; }

[NameInMap("image_url")]
[Validation(Required=true)]
public string ImageUrl { get; set; }

}

}

View file

@ -1,244 +0,0 @@
using System;
using Alipay.EasySDK.Kernel;
using System.Reflection;

namespace Alipay.EasySDK.Factory
{
/// <summary>
/// 客户端工厂用于快速配置和访问各种场景下的API Client
///
/// 注该Factory获取的Client不可储存重复使用请每次均通过Factory完成调用
/// </summary>
public static class Factory
{
public const string SDK_VERSION = "alipay-easysdk-net-2.1.0";

/// <summary>
/// 将一些初始化耗时较多的信息缓存在上下文中
/// </summary>
private static Context context;

/// <summary>
/// 设置客户端参数只需设置一次即可反复使用各种场景下的API Client
/// </summary>
/// <param name="options">客户端参数对象</param>
public static void SetOptions(Config options)
{
context = new Context(options, SDK_VERSION);
}

/// <summary>
/// 获取调用OpenAPI所需的客户端实例
/// 本方法用于调用SDK扩展包中的API Client下的方法
///
/// 注:返回的实例不可重复使用,只可用于单次调用
/// </summary>
/// <typeparam name="T">泛型参数</typeparam>
/// <param name="client">API Client的类型对象</param>
/// <returns>client实例用于发起单次调用</returns>
public static T GetClient<T>()
{
Type type = typeof(T);
ConstructorInfo constructor = type.GetConstructor(new Type[] { typeof(Client) });
context.SdkVersion = GetSdkVersion(type);
return (T)constructor.Invoke(new object[] { new Client(context) });
}

private static string GetSdkVersion(Type client)
{
return context.SdkVersion + "-" + client.FullName
.Replace("EasySDK.", "")
.Replace(".Client", "")
.Replace(".", "-");
}

/// <summary>
/// 基础能力相关
/// </summary>
public static class Base
{
/// <summary>
/// 获取图片相关API Client
/// </summary>
/// <returns>图片相关API Client</returns>
public static EasySDK.Base.Image.Client Image()
{
return new EasySDK.Base.Image.Client(new Client(context));
}

/// <summary>
/// 获取视频相关API Client
/// </summary>
/// <returns>视频相关API Client</returns>
public static EasySDK.Base.Video.Client Video()
{
return new EasySDK.Base.Video.Client(new Client(context));
}

/// <summary>
/// 获取OAuth认证相关API Client
/// </summary>
/// <returns>OAuth认证相关API Client</returns>
public static EasySDK.Base.OAuth.Client OAuth()
{
return new EasySDK.Base.OAuth.Client(new Client(context));
}

/// <summary>
/// 获取小程序二维码相关API Client
/// </summary>
/// <returns>小程序二维码相关API Client</returns>
public static EasySDK.Base.Qrcode.Client Qrcode()
{
return new EasySDK.Base.Qrcode.Client(new Client(context));
}
}

/// <summary>
/// 营销能力相关
/// </summary>
public static class Marketing
{
/// <summary>
/// 获取生活号相关API Client
/// </summary>
/// <returns>生活号相关API Client</returns>
public static EasySDK.Marketing.OpenLife.Client OpenLife()
{
return new EasySDK.Marketing.OpenLife.Client(new Client(context));
}

/// <summary>
/// 获取支付宝卡包相关API Client
/// </summary>
/// <returns>支付宝卡包相关API Client</returns>
public static EasySDK.Marketing.Pass.Client Pass()
{
return new EasySDK.Marketing.Pass.Client(new Client(context));
}

/// <summary>
/// 获取小程序模板消息相关API Client
/// </summary>
/// <returns>小程序模板消息相关API Client</returns>
public static EasySDK.Marketing.TemplateMessage.Client TemplateMessage()
{
return new EasySDK.Marketing.TemplateMessage.Client(new Client(context));
}
}

/// <summary>
/// 会员能力相关
/// </summary>
public static class Member
{
/// <summary>
/// 获取支付宝身份认证相关API Client
/// </summary>
/// <returns>支付宝身份认证相关API Client</returns>
public static EasySDK.Member.Identification.Client Identification()
{
return new EasySDK.Member.Identification.Client(new Client(context));
}
}

/// <summary>
/// 支付能力相关
/// </summary>
public static class Payment
{
/// <summary>
/// 获取支付通用API Client
/// </summary>
/// <returns>支付通用API Client</returns>
public static EasySDK.Payment.Common.Client Common()
{
return new EasySDK.Payment.Common.Client(new Client(context));
}

/// <summary>
/// 获取当面付API Client
/// </summary>
/// <returns>当面付API Client</returns>
public static EasySDK.Payment.FaceToFace.Client FaceToFace()
{
return new EasySDK.Payment.FaceToFace.Client(new Client(context));
}

/// <summary>
/// 获取花呗API Client
/// </summary>
/// <returns>花呗API Client</returns>
public static EasySDK.Payment.Huabei.Client Huabei()
{
return new EasySDK.Payment.Huabei.Client(new Client(context));
}

/// <summary>
/// 获取手机APP支付API Client
/// </summary>
/// <returns>手机APP支付API Client</returns>
public static EasySDK.Payment.App.Client App()
{
return new EasySDK.Payment.App.Client(new Client(context));
}

/// <summary>
/// 获取电脑网站支付API Client
/// </summary>
/// <returns>电脑网站支付API</returns>
public static EasySDK.Payment.Page.Client Page()
{
return new EasySDK.Payment.Page.Client(new Client(context));
}

/// <summary>
/// 获取手机网站支付API Client
/// </summary>
/// <returns>手机网站支付API</returns>
public static EasySDK.Payment.Wap.Client Wap()
{
return new EasySDK.Payment.Wap.Client(new Client(context));
}
}

/// <summary>
/// 安全能力相关
/// </summary>
public static class Security
{
/// <summary>
/// 获取文本风险识别相关API Client
/// </summary>
/// <returns>文本风险识别相关API Client</returns>
public static EasySDK.Security.TextRisk.Client TextRisk()
{
return new EasySDK.Security.TextRisk.Client(new Client(context));
}
}

/// <summary>
/// 辅助工具
/// </summary>
public static class Util
{
/// <summary>
/// 获取OpenAPI通用接口可通过自行拼装参数调用几乎所有OpenAPI
/// </summary>
/// <returns>OpenAPI通用接口</returns>
public static EasySDK.Util.Generic.Client Generic()
{
return new EasySDK.Util.Generic.Client(new Client(context));
}

/// <summary>
/// 获取AES128加解密相关API Client常用于会员手机号的解密
/// </summary>
/// <returns>AES128加解密相关API Client</returns>
public static EasySDK.Util.AES.Client AES()
{
return new EasySDK.Util.AES.Client(new Client(context));
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,37 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class AlipayOpenPublicLifeMsgRecallResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

}

}

View file

@ -1,45 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class AlipayOpenPublicMessageContentCreateResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("content_id")]
[Validation(Required=true)]
public string ContentId { get; set; }

[NameInMap("content_url")]
[Validation(Required=true)]
public string ContentUrl { get; set; }

}

}

View file

@ -1,45 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class AlipayOpenPublicMessageContentModifyResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("content_id")]
[Validation(Required=true)]
public string ContentId { get; set; }

[NameInMap("content_url")]
[Validation(Required=true)]
public string ContentUrl { get; set; }

}

}

View file

@ -1,37 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class AlipayOpenPublicMessageSingleSendResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

}

}

View file

@ -1,41 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class AlipayOpenPublicMessageTotalSendResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("message_id")]
[Validation(Required=true)]
public string MessageId { get; set; }

}

}

View file

@ -1,45 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class AlipayOpenPublicSettingCategoryQueryResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("primary_category")]
[Validation(Required=true)]
public string PrimaryCategory { get; set; }

[NameInMap("secondary_category")]
[Validation(Required=true)]
public string SecondaryCategory { get; set; }

}

}

View file

@ -1,37 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class AlipayOpenPublicTemplateMessageIndustryModifyResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

}

}

View file

@ -1,34 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class Article : TeaModel {
[NameInMap("title")]
[Validation(Required=false)]
public string Title { get; set; }

[NameInMap("desc")]
[Validation(Required=true)]
public string Desc { get; set; }

[NameInMap("image_url")]
[Validation(Required=false)]
public string ImageUrl { get; set; }

[NameInMap("url")]
[Validation(Required=true)]
public string Url { get; set; }

[NameInMap("action_name")]
[Validation(Required=false)]
public string ActionName { get; set; }

}

}

View file

@ -1,42 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class Context : TeaModel {
[NameInMap("head_color")]
[Validation(Required=true)]
public string HeadColor { get; set; }

[NameInMap("url")]
[Validation(Required=true)]
public string Url { get; set; }

[NameInMap("action_name")]
[Validation(Required=true)]
public string ActionName { get; set; }

[NameInMap("keyword1")]
[Validation(Required=false)]
public Keyword Keyword1 { get; set; }

[NameInMap("keyword2")]
[Validation(Required=false)]
public Keyword Keyword2 { get; set; }

[NameInMap("first")]
[Validation(Required=false)]
public Keyword First { get; set; }

[NameInMap("remark")]
[Validation(Required=false)]
public Keyword Remark { get; set; }

}

}

View file

@ -1,22 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class Keyword : TeaModel {
[NameInMap("color")]
[Validation(Required=true)]
public string Color { get; set; }

[NameInMap("value")]
[Validation(Required=true)]
public string Value { get; set; }

}

}

View file

@ -1,22 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class Template : TeaModel {
[NameInMap("template_id")]
[Validation(Required=true)]
public string TemplateId { get; set; }

[NameInMap("context")]
[Validation(Required=true)]
public Context Context { get; set; }

}

}

View file

@ -1,22 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.OpenLife.Models
{
public class Text : TeaModel {
[NameInMap("title")]
[Validation(Required=true)]
public string Title { get; set; }

[NameInMap("content")]
[Validation(Required=true)]
public string Content { get; set; }

}

}

View file

@ -1,964 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

using Tea;
using Tea.Utils;

using Alipay.EasySDK.Marketing.Pass.Models;

namespace Alipay.EasySDK.Marketing.Pass
{
public class Client
{
protected Alipay.EasySDK.Kernel.Client _kernel;

public Client(Alipay.EasySDK.Kernel.Client kernel)
{
this._kernel = kernel;
}

public AlipayPassTemplateAddResponse CreateTemplate(string uniqueId, string tplContent)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.pass.template.add"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"unique_id", uniqueId},
{"tpl_content", tplContent},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.pass.template.add");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayPassTemplateAddResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayPassTemplateAddResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipayPassTemplateAddResponse> CreateTemplateAsync(string uniqueId, string tplContent)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.pass.template.add"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"unique_id", uniqueId},
{"tpl_content", tplContent},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.pass.template.add");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayPassTemplateAddResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayPassTemplateAddResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public AlipayPassTemplateUpdateResponse UpdateTemplate(string tplId, string tplContent)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.pass.template.update"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"tpl_id", tplId},
{"tpl_content", tplContent},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.pass.template.update");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayPassTemplateUpdateResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayPassTemplateUpdateResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipayPassTemplateUpdateResponse> UpdateTemplateAsync(string tplId, string tplContent)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.pass.template.update"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"tpl_id", tplId},
{"tpl_content", tplContent},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.pass.template.update");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayPassTemplateUpdateResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayPassTemplateUpdateResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public AlipayPassInstanceAddResponse AddInstance(string tplId, string tplParams, string recognitionType, string recognitionInfo)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.pass.instance.add"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"tpl_id", tplId},
{"tpl_params", tplParams},
{"recognition_type", recognitionType},
{"recognition_info", recognitionInfo},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.pass.instance.add");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayPassInstanceAddResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayPassInstanceAddResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipayPassInstanceAddResponse> AddInstanceAsync(string tplId, string tplParams, string recognitionType, string recognitionInfo)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.pass.instance.add"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"tpl_id", tplId},
{"tpl_params", tplParams},
{"recognition_type", recognitionType},
{"recognition_info", recognitionInfo},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.pass.instance.add");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayPassInstanceAddResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayPassInstanceAddResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public AlipayPassInstanceUpdateResponse UpdateInstance(string serialNumber, string channelId, string tplParams, string status, string verifyCode, string verifyType)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.pass.instance.update"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"serial_number", serialNumber},
{"channel_id", channelId},
{"tpl_params", tplParams},
{"status", status},
{"verify_code", verifyCode},
{"verify_type", verifyType},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.pass.instance.update");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayPassInstanceUpdateResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayPassInstanceUpdateResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipayPassInstanceUpdateResponse> UpdateInstanceAsync(string serialNumber, string channelId, string tplParams, string status, string verifyCode, string verifyType)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.pass.instance.update"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"serial_number", serialNumber},
{"channel_id", channelId},
{"tpl_params", tplParams},
{"status", status},
{"verify_code", verifyCode},
{"verify_type", verifyType},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.pass.instance.update");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayPassInstanceUpdateResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayPassInstanceUpdateResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

/// <summary>
/// ISV代商户代用指定appAuthToken
/// </summary>
/// <param name="appAuthToken">代调用token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Agent(string appAuthToken)
{
_kernel.InjectTextParam("app_auth_token", appAuthToken);
return this;
}

/// <summary>
/// 用户授权调用指定authToken
/// </summary>
/// <param name="authToken">用户授权token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Auth(string authToken)
{
_kernel.InjectTextParam("auth_token", authToken);
return this;
}

/// <summary>
/// 设置异步通知回调地址此处设置将在本调用中覆盖Config中的全局配置
/// </summary>
/// <param name="url">异步通知回调地址例如https://www.test.com/callback </param>
/// <returns>本客户端,便于链式调用</returns>
public Client AsyncNotify(string url)
{
_kernel.InjectTextParam("notify_url", url);
return this;
}

/// <summary>
/// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效
/// </summary>
/// <param name="testUrl">后端系统测试地址</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Route(string testUrl)
{
_kernel.InjectTextParam("ws_service_url", testUrl);
return this;
}

/// <summary>
/// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// </summary>
/// <param name="key">业务请求参数名称biz_content下的字段名比如timeout_express</param>
/// <param name="value">
/// 业务请求参数的值一个可以序列化成JSON的对象
/// 如果该字段是一个字符串类型String、Price、Date在SDK中都是字符串请使用string储存
/// 如果该字段是一个数值型类型比如Number请使用long储存
/// 如果该字段是一个复杂类型请使用嵌套的Dictionary指定各下级字段的值
/// 如果该字段是一个数组请使用List储存各个值
/// 对于更复杂的情况也支持Dictionary和List的各种组合嵌套比如参数是值是个ListList中的每种类型是一个复杂对象
/// </param>
/// <returns>本客户端,便于链式调用</returns>
public Client Optional(string key, object value)
{
_kernel.InjectBizParam(key, value);
return this;
}

/// <summary>
/// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// optional方法的批量版本
/// </summary>
/// <param name="optionalArgs">可选参数集合每个参数由key和value组成key和value的格式请参见optional方法的注释</param>
/// <returns>本客户端,便于链式调用</returns>
public Client BatchOptional(Dictionary<string, object> optionalArgs)
{
foreach (var pair in optionalArgs)
{
_kernel.InjectBizParam(pair.Key, pair.Value);
}
return this;
}
}
}

View file

@ -1,45 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.Pass.Models
{
public class AlipayPassInstanceAddResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("success")]
[Validation(Required=true)]
public bool? Success { get; set; }

[NameInMap("result")]
[Validation(Required=true)]
public string Result { get; set; }

}

}

View file

@ -1,45 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.Pass.Models
{
public class AlipayPassInstanceUpdateResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("success")]
[Validation(Required=true)]
public bool? Success { get; set; }

[NameInMap("result")]
[Validation(Required=true)]
public string Result { get; set; }

}

}

View file

@ -1,45 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.Pass.Models
{
public class AlipayPassTemplateAddResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("success")]
[Validation(Required=true)]
public bool? Success { get; set; }

[NameInMap("result")]
[Validation(Required=true)]
public string Result { get; set; }

}

}

View file

@ -1,45 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.Pass.Models
{
public class AlipayPassTemplateUpdateResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("success")]
[Validation(Required=true)]
public bool? Success { get; set; }

[NameInMap("result")]
[Validation(Required=true)]
public string Result { get; set; }

}

}

View file

@ -1,322 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

using Tea;
using Tea.Utils;

using Alipay.EasySDK.Marketing.TemplateMessage.Models;

namespace Alipay.EasySDK.Marketing.TemplateMessage
{
public class Client
{
protected Alipay.EasySDK.Kernel.Client _kernel;

public Client(Alipay.EasySDK.Kernel.Client kernel)
{
this._kernel = kernel;
}

public AlipayOpenAppMiniTemplatemessageSendResponse Send(string toUserId, string formId, string userTemplateId, string page, string data)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.open.app.mini.templatemessage.send"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"to_user_id", toUserId},
{"form_id", formId},
{"user_template_id", userTemplateId},
{"page", page},
{"data", data},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.open.app.mini.templatemessage.send");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayOpenAppMiniTemplatemessageSendResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayOpenAppMiniTemplatemessageSendResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipayOpenAppMiniTemplatemessageSendResponse> SendAsync(string toUserId, string formId, string userTemplateId, string page, string data)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.open.app.mini.templatemessage.send"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"to_user_id", toUserId},
{"form_id", formId},
{"user_template_id", userTemplateId},
{"page", page},
{"data", data},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.open.app.mini.templatemessage.send");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayOpenAppMiniTemplatemessageSendResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayOpenAppMiniTemplatemessageSendResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

/// <summary>
/// ISV代商户代用指定appAuthToken
/// </summary>
/// <param name="appAuthToken">代调用token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Agent(string appAuthToken)
{
_kernel.InjectTextParam("app_auth_token", appAuthToken);
return this;
}

/// <summary>
/// 用户授权调用指定authToken
/// </summary>
/// <param name="authToken">用户授权token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Auth(string authToken)
{
_kernel.InjectTextParam("auth_token", authToken);
return this;
}

/// <summary>
/// 设置异步通知回调地址此处设置将在本调用中覆盖Config中的全局配置
/// </summary>
/// <param name="url">异步通知回调地址例如https://www.test.com/callback </param>
/// <returns>本客户端,便于链式调用</returns>
public Client AsyncNotify(string url)
{
_kernel.InjectTextParam("notify_url", url);
return this;
}

/// <summary>
/// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效
/// </summary>
/// <param name="testUrl">后端系统测试地址</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Route(string testUrl)
{
_kernel.InjectTextParam("ws_service_url", testUrl);
return this;
}

/// <summary>
/// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// </summary>
/// <param name="key">业务请求参数名称biz_content下的字段名比如timeout_express</param>
/// <param name="value">
/// 业务请求参数的值一个可以序列化成JSON的对象
/// 如果该字段是一个字符串类型String、Price、Date在SDK中都是字符串请使用string储存
/// 如果该字段是一个数值型类型比如Number请使用long储存
/// 如果该字段是一个复杂类型请使用嵌套的Dictionary指定各下级字段的值
/// 如果该字段是一个数组请使用List储存各个值
/// 对于更复杂的情况也支持Dictionary和List的各种组合嵌套比如参数是值是个ListList中的每种类型是一个复杂对象
/// </param>
/// <returns>本客户端,便于链式调用</returns>
public Client Optional(string key, object value)
{
_kernel.InjectBizParam(key, value);
return this;
}

/// <summary>
/// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// optional方法的批量版本
/// </summary>
/// <param name="optionalArgs">可选参数集合每个参数由key和value组成key和value的格式请参见optional方法的注释</param>
/// <returns>本客户端,便于链式调用</returns>
public Client BatchOptional(Dictionary<string, object> optionalArgs)
{
foreach (var pair in optionalArgs)
{
_kernel.InjectBizParam(pair.Key, pair.Value);
}
return this;
}
}
}

View file

@ -1,37 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Marketing.TemplateMessage.Models
{
public class AlipayOpenAppMiniTemplatemessageSendResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

}

}

View file

@ -1,562 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

using Tea;
using Tea.Utils;

using Alipay.EasySDK.Member.Identification.Models;

namespace Alipay.EasySDK.Member.Identification
{
public class Client
{
protected Alipay.EasySDK.Kernel.Client _kernel;

public Client(Alipay.EasySDK.Kernel.Client kernel)
{
this._kernel = kernel;
}

public AlipayUserCertifyOpenInitializeResponse Init(string outerOrderNo, string bizCode, IdentityParam identityParam, MerchantConfig merchantConfig)
{
identityParam.Validate();
merchantConfig.Validate();
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.user.certify.open.initialize"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"outer_order_no", outerOrderNo},
{"biz_code", bizCode},
{"identity_param", identityParam},
{"merchant_config", merchantConfig},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.user.certify.open.initialize");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayUserCertifyOpenInitializeResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayUserCertifyOpenInitializeResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipayUserCertifyOpenInitializeResponse> InitAsync(string outerOrderNo, string bizCode, IdentityParam identityParam, MerchantConfig merchantConfig)
{
identityParam.Validate();
merchantConfig.Validate();
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.user.certify.open.initialize"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"outer_order_no", outerOrderNo},
{"biz_code", bizCode},
{"identity_param", identityParam},
{"merchant_config", merchantConfig},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.user.certify.open.initialize");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayUserCertifyOpenInitializeResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayUserCertifyOpenInitializeResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public AlipayUserCertifyOpenQueryResponse Query(string certifyId)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.user.certify.open.query"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"certify_id", certifyId},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

Dictionary<string, object> respMap = this._kernel.ReadAsJson(response_, "alipay.user.certify.open.query");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayUserCertifyOpenQueryResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayUserCertifyOpenQueryResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public async Task<AlipayUserCertifyOpenQueryResponse> QueryAsync(string certifyId)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"ignoreSSL", this._kernel.GetConfig("ignoreSSL")},
{"httpProxy", this._kernel.GetConfig("httpProxy")},
{"connectTimeout", 15000},
{"readTimeout", 15000},
{"retry", new Dictionary<string, int?>
{
{"maxAttempts", 0},
}},
};

TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary)runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.user.certify.open.query"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"certify_id", certifyId},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
request_.Protocol = this._kernel.GetConfig("protocol");
request_.Method = "POST";
request_.Pathname = "/gateway.do";
request_.Headers = new Dictionary<string, string>
{
{"host", this._kernel.GetConfig("gatewayHost")},
{"content-type", "application/x-www-form-urlencoded;charset=utf-8"},
};
request_.Query = this._kernel.SortMap(TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"sign", this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"))},
},
systemParams,
textParams
));
request_.Body = TeaCore.BytesReadable(this._kernel.ToUrlEncodedRequestBody(bizParams));
_lastRequest = request_;
TeaResponse response_ = await TeaCore.DoActionAsync(request_, runtime_);

Dictionary<string, object> respMap = await this._kernel.ReadAsJsonAsync(response_, "alipay.user.certify.open.query");
if (this._kernel.IsCertMode())
{
if (this._kernel.Verify(respMap, this._kernel.ExtractAlipayPublicKey(this._kernel.GetAlipayCertSN(respMap))))
{
return TeaModel.ToObject<AlipayUserCertifyOpenQueryResponse>(this._kernel.ToRespModel(respMap));
}
}
else
{
if (this._kernel.Verify(respMap, this._kernel.GetConfig("alipayPublicKey")))
{
return TeaModel.ToObject<AlipayUserCertifyOpenQueryResponse>(this._kernel.ToRespModel(respMap));
}
}
throw new TeaException(new Dictionary<string, string>
{
{"message", "验签失败,请检查支付宝公钥设置是否正确。"},
});
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw e;
}
}

throw new TeaUnretryableException(_lastRequest, _lastException);
}

public AlipayUserCertifyOpenCertifyResponse Certify(string certifyId)
{
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.user.certify.open.certify"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"certify_id", certifyId},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
string sign = this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"));
Dictionary<string, string> response = new Dictionary<string, string>
{
{"body", this._kernel.GeneratePage("GET", systemParams, bizParams, textParams, sign)},
};
return TeaModel.ToObject<AlipayUserCertifyOpenCertifyResponse>(response);
}

/// <summary>
/// ISV代商户代用指定appAuthToken
/// </summary>
/// <param name="appAuthToken">代调用token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Agent(string appAuthToken)
{
_kernel.InjectTextParam("app_auth_token", appAuthToken);
return this;
}

/// <summary>
/// 用户授权调用指定authToken
/// </summary>
/// <param name="authToken">用户授权token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Auth(string authToken)
{
_kernel.InjectTextParam("auth_token", authToken);
return this;
}

/// <summary>
/// 设置异步通知回调地址此处设置将在本调用中覆盖Config中的全局配置
/// </summary>
/// <param name="url">异步通知回调地址例如https://www.test.com/callback </param>
/// <returns>本客户端,便于链式调用</returns>
public Client AsyncNotify(string url)
{
_kernel.InjectTextParam("notify_url", url);
return this;
}

/// <summary>
/// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效
/// </summary>
/// <param name="testUrl">后端系统测试地址</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Route(string testUrl)
{
_kernel.InjectTextParam("ws_service_url", testUrl);
return this;
}

/// <summary>
/// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// </summary>
/// <param name="key">业务请求参数名称biz_content下的字段名比如timeout_express</param>
/// <param name="value">
/// 业务请求参数的值一个可以序列化成JSON的对象
/// 如果该字段是一个字符串类型String、Price、Date在SDK中都是字符串请使用string储存
/// 如果该字段是一个数值型类型比如Number请使用long储存
/// 如果该字段是一个复杂类型请使用嵌套的Dictionary指定各下级字段的值
/// 如果该字段是一个数组请使用List储存各个值
/// 对于更复杂的情况也支持Dictionary和List的各种组合嵌套比如参数是值是个ListList中的每种类型是一个复杂对象
/// </param>
/// <returns>本客户端,便于链式调用</returns>
public Client Optional(string key, object value)
{
_kernel.InjectBizParam(key, value);
return this;
}

/// <summary>
/// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// optional方法的批量版本
/// </summary>
/// <param name="optionalArgs">可选参数集合每个参数由key和value组成key和value的格式请参见optional方法的注释</param>
/// <returns>本客户端,便于链式调用</returns>
public Client BatchOptional(Dictionary<string, object> optionalArgs)
{
foreach (var pair in optionalArgs)
{
_kernel.InjectBizParam(pair.Key, pair.Value);
}
return this;
}
}
}

View file

@ -1,21 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Member.Identification.Models
{
public class AlipayUserCertifyOpenCertifyResponse : TeaModel {
/// <summary>
/// 认证服务请求地址
/// </summary>
[NameInMap("body")]
[Validation(Required=true)]
public string Body { get; set; }

}

}

View file

@ -1,41 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Member.Identification.Models
{
public class AlipayUserCertifyOpenInitializeResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("certify_id")]
[Validation(Required=true)]
public string CertifyId { get; set; }

}

}

View file

@ -1,49 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Member.Identification.Models
{
public class AlipayUserCertifyOpenQueryResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("passed")]
[Validation(Required=true)]
public string Passed { get; set; }

[NameInMap("identity_info")]
[Validation(Required=true)]
public string IdentityInfo { get; set; }

[NameInMap("material_info")]
[Validation(Required=true)]
public string MaterialInfo { get; set; }

}

}

View file

@ -1,30 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Member.Identification.Models
{
public class IdentityParam : TeaModel {
[NameInMap("identity_type")]
[Validation(Required=true)]
public string IdentityType { get; set; }

[NameInMap("cert_type")]
[Validation(Required=true)]
public string CertType { get; set; }

[NameInMap("cert_name")]
[Validation(Required=true)]
public string CertName { get; set; }

[NameInMap("cert_no")]
[Validation(Required=true)]
public string CertNo { get; set; }

}

}

View file

@ -1,18 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Member.Identification.Models
{
public class MerchantConfig : TeaModel {
[NameInMap("return_url")]
[Validation(Required=true)]
public string ReturnUrl { get; set; }

}

}

View file

@ -1,135 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

using Tea;
using Tea.Utils;

using Alipay.EasySDK.Payment.App.Models;

namespace Alipay.EasySDK.Payment.App
{
public class Client
{
protected Alipay.EasySDK.Kernel.Client _kernel;

public Client(Alipay.EasySDK.Kernel.Client kernel)
{
this._kernel = kernel;
}


public AlipayTradeAppPayResponse Pay(string subject, string outTradeNo, string totalAmount)
{
Dictionary<string, string> systemParams = new Dictionary<string, string>
{
{"method", "alipay.trade.app.pay"},
{"app_id", this._kernel.GetConfig("appId")},
{"timestamp", this._kernel.GetTimestamp()},
{"format", "json"},
{"version", "1.0"},
{"alipay_sdk", this._kernel.GetSdkVersion()},
{"charset", "UTF-8"},
{"sign_type", this._kernel.GetConfig("signType")},
{"app_cert_sn", this._kernel.GetMerchantCertSN()},
{"alipay_root_cert_sn", this._kernel.GetAlipayRootCertSN()},
};
Dictionary<string, object> bizParams = new Dictionary<string, object>
{
{"subject", subject},
{"out_trade_no", outTradeNo},
{"total_amount", totalAmount},
};
Dictionary<string, string> textParams = new Dictionary<string, string>(){};
string sign = this._kernel.Sign(systemParams, bizParams, textParams, this._kernel.GetConfig("merchantPrivateKey"));
Dictionary<string, string> response = new Dictionary<string, string>
{
{"body", this._kernel.GenerateOrderString(systemParams, bizParams, textParams, sign)},
};
return TeaModel.ToObject<AlipayTradeAppPayResponse>(response);
}

/// <summary>
/// ISV代商户代用指定appAuthToken
/// </summary>
/// <param name="appAuthToken">代调用token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Agent(string appAuthToken)
{
_kernel.InjectTextParam("app_auth_token", appAuthToken);
return this;
}

/// <summary>
/// 用户授权调用指定authToken
/// </summary>
/// <param name="authToken">用户授权token</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Auth(string authToken)
{
_kernel.InjectTextParam("auth_token", authToken);
return this;
}

/// <summary>
/// 设置异步通知回调地址此处设置将在本调用中覆盖Config中的全局配置
/// </summary>
/// <param name="url">异步通知回调地址例如https://www.test.com/callback </param>
/// <returns>本客户端,便于链式调用</returns>
public Client AsyncNotify(string url)
{
_kernel.InjectTextParam("notify_url", url);
return this;
}

/// <summary>
/// 将本次调用强制路由到后端系统的测试地址上,常用于线下环境内外联调,沙箱与线上环境设置无效
/// </summary>
/// <param name="testUrl">后端系统测试地址</param>
/// <returns>本客户端,便于链式调用</returns>
public Client Route(string testUrl)
{
_kernel.InjectTextParam("ws_service_url", testUrl);
return this;
}

/// <summary>
/// 设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// </summary>
/// <param name="key">业务请求参数名称biz_content下的字段名比如timeout_express</param>
/// <param name="value">
/// 业务请求参数的值一个可以序列化成JSON的对象
/// 如果该字段是一个字符串类型String、Price、Date在SDK中都是字符串请使用string储存
/// 如果该字段是一个数值型类型比如Number请使用long储存
/// 如果该字段是一个复杂类型请使用嵌套的Dictionary指定各下级字段的值
/// 如果该字段是一个数组请使用List储存各个值
/// 对于更复杂的情况也支持Dictionary和List的各种组合嵌套比如参数是值是个ListList中的每种类型是一个复杂对象
/// </param>
/// <returns>本客户端,便于链式调用</returns>
public Client Optional(string key, object value)
{
_kernel.InjectBizParam(key, value);
return this;
}

/// <summary>
/// 批量设置API入参中没有的其他可选业务请求参数(biz_content下的字段)
/// optional方法的批量版本
/// </summary>
/// <param name="optionalArgs">可选参数集合每个参数由key和value组成key和value的格式请参见optional方法的注释</param>
/// <returns>本客户端,便于链式调用</returns>
public Client BatchOptional(Dictionary<string, object> optionalArgs)
{
foreach (var pair in optionalArgs)
{
_kernel.InjectBizParam(pair.Key, pair.Value);
}
return this;
}
}
}

View file

@ -1,21 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Payment.App.Models
{
public class AlipayTradeAppPayResponse : TeaModel {
/// <summary>
/// 订单信息,字符串形式
/// </summary>
[NameInMap("body")]
[Validation(Required=true)]
public string Body { get; set; }

}

}

File diff suppressed because it is too large Load diff

View file

@ -1,41 +0,0 @@
// This file is auto-generated, don't edit it. Thanks.

using System;
using System.Collections.Generic;
using System.IO;

using Tea;

namespace Alipay.EasySDK.Payment.Common.Models
{
public class AlipayDataDataserviceBillDownloadurlQueryResponse : TeaModel {
/// <summary>
/// 响应原始字符串
/// </summary>
[NameInMap("http_body")]
[Validation(Required=true)]
public string HttpBody { get; set; }

[NameInMap("code")]
[Validation(Required=true)]
public string Code { get; set; }

[NameInMap("msg")]
[Validation(Required=true)]
public string Msg { get; set; }

[NameInMap("sub_code")]
[Validation(Required=true)]
public string SubCode { get; set; }

[NameInMap("sub_msg")]
[Validation(Required=true)]
public string SubMsg { get; set; }

[NameInMap("bill_download_url")]
[Validation(Required=true)]
public string BillDownloadUrl { get; set; }

}

}

Some files were not shown because too many files have changed in this diff Show more